A Million Monkeys (Doing Geometry)
Hypothetically, let's say that you didn't much care for high school, begrudgingly (and briefly) attended college, slavedaway as a salariedminion for years, turned free-lance, and found yourself in the position of needing to migrate geometry data from MapInfoSpatialWare running on SQL Server to PostGIS running on PostgreSQL, and a million monkeys were not immediately available to assist. You might do the following:
package net.stygian;
//
// SwToPg.java
// Chimaera
//
// Created by Curtis Jones on 2005.10.18.
// Copyright 2005 Symphonic Systems, Inc. All rights reserved.
//
// Revision 2005.10.18.001
//
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
public class SwToPg {
protected static final int MAX_TYPE_LENG = 32;
protected static final String[] sw_types = {
"ST_Spatial(",
"ST_Polygon(",
"HG_DirectionForward(",
"ST_Path(",
"ST_Polyline(",
"LIST{",
"ST_Point("
};
protected static final Geometry[] sw_classes = {
new SW_ST_Spatial(),
new SW_ST_Polygon(),
new SW_HG_DirectionForward(),
new SW_ST_Path(),
new SW_ST_Polyline(),
new SW_List(),
new SW_ST_Point()
};
/**
*
*
*
*/
public static int convert (InputStream is,
OutputStream os) throws Exception {
Geometry g = null;
while (null != (g = getGeometryForToken(getNextToken(is, os))))
g.output(is, os);
return 1;
}
protected static abstract class Geometry {
public abstract void output (InputStream is,
OutputStream os)
throws Exception;
}
protected static class SW_ST_Spatial extends Geometry {
public void output (InputStream is,
OutputStream os) throws Exception {
os.write("GEOMETRYCOLLECTION(".getBytes());
SwToPg.convert(is, os);
os.write(")".getBytes());
}
}
protected static class SW_ST_Polygon extends Geometry {
public void output (InputStream is,
OutputStream os) throws Exception {
os.write("POLYGON((".getBytes());
SwToPg.convert(is, os);
os.write("))".getBytes());
}
}
protected static class SW_ST_Point extends Geometry {
public void output (InputStream is,
OutputStream os) throws Exception {
String n1 = SwToPg.readUntil(is, (byte)',', 32);
String n2 = SwToPg.readUntil(is, (byte)')', 32);
os.write("POINT(".getBytes());
os.write(n1.getBytes());
os.write(" ".getBytes());
os.write(n2.getBytes());
os.write(")".getBytes());
}
}
protected static class SW_HG_DirectionForward extends Geometry {
public void output (InputStream is,
OutputStream os) throws Exception {
SwToPg.convert(is, os);
}
}
protected static class SW_List extends Geometry {
public void output (InputStream is,
OutputStream os) throws Exception {
SwToPg.convert(is, os);
}
}
protected static class SW_ST_Polyline extends Geometry {
public void output (InputStream is,
OutputStream os) throws Exception {
SwToPg.convert(is, os);
}
}
protected static class SW_ST_Path extends Geometry {
public void output (InputStream is,
OutputStream os) throws Exception {
SwToPg.convert(is, os);
}
}
/**
* Returns the first instance of a set of characters
* followed by a '(' or a '{'. The max length is
* MAX_TYPE_LENG. If the max is reached, then whatever
* has been read is returned.
*
*/
public static String getNextToken (InputStream is,
OutputStream os) {
if (is == null)
return null;
try {
byte[] token = new byte[MAX_TYPE_LENG];
int type_leng = 0;
for (; type_leng < token.length; ++type_leng) {
int read_leng = is.read(token, type_leng, 1);
if (read_leng == -1)
return null;
if (token[type_leng] == ',') {
os.write(",".getBytes());
type_leng--;
continue;
}
else if (token[type_leng] == ')' || token[type_leng] == '}')
return null;
if (token[type_leng] == '(' || token[type_leng] == '{')
break;
}
return new String(token, 0, type_leng+1);
}
catch (Exception e) {
System.err.println("SwToPg::getNextToken().. " +
e.getMessage());
e.printStackTrace();
}
return null;
}
/**
* Takes a String token, such as that returned by
* getNextToken(), which should match one of the
* entries in the "sw_types" array, and returns
* a new and corresponding Geometry instance.
*
*/
public static Geometry getGeometryForToken (String token) {
if (token == null || token.length() == 0)
return null;
for (int type_pos = 0; type_pos < sw_types.length; ++type_pos)
if (token.equals(sw_types[type_pos]))
return (Geometry)sw_classes[type_pos];
return null;
}
/**
* Reads from the InputStream (is) up until (and including)
* the first byte which matches the stop-byte (b), or until
* the read length reaches the specified limit (max).
*
* If the max is reached, then whatever has been read so
* far is returned. If the stop-byte is found, it is remove
* from the InputStream (is), but it is not included in the
* returned String.
*
*/
public static String readUntil (InputStream is,
byte b,
int max) throws Exception {
if (max > 50)
throw new Exception("SwToPg::readUntil().. specified 'max' " +
"exceeds limit: " + max);
try {
byte[] token = new byte[MAX_TYPE_LENG];
int type_leng = 0;
for (; type_leng < token.length; ++type_leng) {
is.read(token, type_leng, 1);
if (token[type_leng] == b)
break;
}
return new String(token, 0, type_leng);
}
catch (Exception e) {
System.err.println("SwToPg::readUntil().. " +
e.getMessage());
e.printStackTrace();
}
return null;
}
/**
* Input - string form of spatialware geometry data
*
* EXEC sp_spatial_query 'SELECT HG_GetString(sw_geometry)
* FROM igsubmarkets'
*
*
* Output - sql to represent the same geometries in
* postgres/postgis
*
*/
public static void main (String[] args) throws Exception {
InputStream i = null;
OutputStream o = null;
for (int args_pos = 0; args_pos < args.length; ++args_pos) {
if (args[args_pos].equals("-i"))
i = new FileInputStream(args[++args_pos]);
else if (args[args_pos].equals("-o"))
o = new FileOutputStream(args[++args_pos]);
else
throw new Exception("Unsupported flag, " + args[args_pos]);
}
if (i == null) i = System.in;
if (o == null) o = System.out;
SwToPg.convert(i, o);
}
}
Or you might not. It's hard to tell with some people.