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.

Subscribe to A garage sale for your mind

Don’t miss out on the latest posts. Sign up now to get access to the library of members-only posts.
[email protected]
Subscribe