A Million Monkeys (Doing Geometry)
Hypothetically, say you need to migrate geometry data from MapInfo SpatialWare on SQL Server to PostGIS on PostgreSQL, and a million monkeys aren't available to help. You might write this Java. Or you might not. It's hard to tell with some people.
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.