AW: [OpenMap Users] Street labels

From: Gubler, Ruediger <rgubler_at_init-ka.de>
Date: Tue, 22 Mar 2005 08:37:09 +0100

Hi Cary,

we use the follwing class. It needs the jts jar from http://www.vividsolutions.com/products.asp?catg=spaapp&code=jts.


package com.initka.bprocess.gis.display2.objects;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.RenderingHints;
import java.awt.font.FontRenderContext;
import java.awt.font.LineMetrics;
import java.awt.geom.AffineTransform;
import java.io.Serializable;
import java.util.List;
import java.util.ListIterator;
import java.util.Vector;

import com.bbn.openmap.omGraphics.OMGraphic;
import com.bbn.openmap.proj.Projection;

import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Geometry;
import com.vividsolutions.jts.geom.GeometryFactory;
import com.vividsolutions.jts.geom.LineString;
import com.vividsolutions.jts.geom.LinearRing;
import com.vividsolutions.jts.geom.Polygon;
import com.vividsolutions.jts.geom.PrecisionModel;

/**
 *
 * _at_author rgu
 * _at_version $Revision: 1.1 $
 */
public class GisOMPolyLabel extends OMGraphic implements Serializable
{
  public final static String VM_VERSION = "$Revision: 1.1 $";
  public static final long serialVersionUID = 1L;
  private final static int MinDistFactor = 3;
  private final static double HalfPI = Math.PI / 2;
  private final static double ThreePIhalf = 3 * Math.PI / 2;
  private final static double TwoPI = 2 * Math.PI;
  private float[] _sequence;
  private String _text;
  private int[][] _lines;
  private int[] _bounds;
  private Font _font;
  private Color _textColor;
  private boolean _shouldRepeatName;

  public GisOMPolyLabel(
    String text,
    float[] sequence,
    int[] bounds,
    Font font,
    Color textColor,
    boolean shouldRepeatName)
  {
    _text = text;
    _sequence = sequence;
    _font = font;
    _textColor = textColor;
    _bounds = bounds;
    _shouldRepeatName = shouldRepeatName;
  }

  public boolean generate(Projection proj)
  {
    int[] polyline = new int[_sequence.length];
    for (int ii = 0; ii < polyline.length - 1; ii += 2)
    {
      float lat = _sequence[ii];
      float lon = _sequence[ii + 1];
      Point p = proj.forward(lat, lon);
      polyline[ii] = p.y;
      polyline[ii + 1] = p.x;
    }
    _lines = splittInParts(polyline, _bounds);
    return true;
  }

  public void render(Graphics graphics)
  {
    Graphics2D gfx2 = (Graphics2D) graphics;

    boolean alreadyPainted = false;
    double partDist = 0D;
    double textWidth = gfx2.getFontMetrics().getStringBounds(_text, gfx2).getWidth();

    gfx2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    gfx2.setFont(_font);
    gfx2.setColor(_textColor);

    for (int part = 0; part < _lines.length; part++)
    {
      double dPhi, dLength;
      int[] subLine = _lines[part];

      for (int ii = 0; ii < subLine.length - 3; ii += 2)
      {
        double y1 = subLine[ii];
        double x1 = subLine[ii + 1];
        double y2 = subLine[ii + 2];
        double x2 = subLine[ii + 3];

        dLength = Math.sqrt((y2 - y1) * (y2 - y1) + (x2 - x1) * (x2 - x1));
        if (dLength >= textWidth && (!alreadyPainted || partDist == 0 || partDist > (textWidth * MinDistFactor)))
        {
          alreadyPainted = true;
          partDist = 0;
          if (checkReverse(new double[] { y1, x1, y2, x2 }))
          {
            double tmpX = x1;
            double tmpY = y1;
            x1 = x2;
            y1 = y2;
            x2 = tmpX;
            y2 = tmpY;
          }

          dPhi = Math.atan2(y2 - y1, x2 - x1);

          int x3 = (int) (x1 + ((dLength - textWidth) / 2));
          FontRenderContext defaultcontext = new FontRenderContext(new AffineTransform(), true, true);
          LineMetrics metrics = _font.getLineMetrics(_text, defaultcontext);
          int y3 = (int) (y1 + (metrics.getAscent() - metrics.getDescent()) / 2);

          gfx2.rotate(dPhi, x1, y1);
          gfx2.drawString(_text, x3, y3);
          gfx2.rotate(-dPhi, x1, y1);
          if (!_shouldRepeatName)
            return;
        }
        partDist += dLength;
      }
    }
  }

  private int[][] splittInParts(int[] line, int[] bounds)
  {
    Vector retVec = new Vector();
    Vector partCoords = new Vector();
    Coordinate oldCoord = null;
    LinearRing[] holes = null;
    PrecisionModel pm = new PrecisionModel(PrecisionModel.FLOATING);
    GeometryFactory gf = new GeometryFactory(pm);
    Coordinate[] polyCoords = new Coordinate[bounds.length / 2];
    for (int ii = 0; ii < polyCoords.length; ii++)
    {
      int xpos = (2 * ii) + 1;
      int ypos = (2 * ii);
      polyCoords[ii] = new Coordinate(bounds[xpos], bounds[ypos]);
    }
    LinearRing shell = gf.createLinearRing(polyCoords);
    Polygon poly = gf.createPolygon(shell, holes);
    for (int part = 0; part < line.length - 3; part += 2)
    {
      Coordinate[] lineCoords = new Coordinate[2];
      lineCoords[0] = new Coordinate(line[part + 1], line[part]);
      lineCoords[1] = new Coordinate(line[part + 3], line[part + 2]);
      LineString ls = gf.createLineString(lineCoords);
      Geometry geom = poly.intersection(ls);
      Coordinate[] coords = geom.getCoordinates();
      for (int ii = 0; coords.length > 1 && ii < coords.length - 1; ii += 2)
      {
        Coordinate coord_1 = coords[ii];
        Coordinate coord_2 = coords[ii + 1];
        if (oldCoord == null || oldCoord.equals2D(coord_1))
        {
          if (oldCoord == null || !oldCoord.equals2D(coord_1))
          {
            partCoords.add(coord_1);
          }
          partCoords.add(coord_2);
        }
        else
        {
          retVec.add(partCoords);
          partCoords = new Vector();
          partCoords.add(coord_1);
          partCoords.add(coord_2);
        }
        oldCoord = coord_2;
      }
    }
    retVec.add(partCoords);
    return makeCoords2Array(retVec);
  }

  private int[][] makeCoords2Array(List list)
  {
    int[][] retArr = new int[list.size()][];
    for (int ii = 0; ii < list.size(); ii++)
    {
      List innerList = (List) list.get(ii);
      retArr[ii] = getIntArray(innerList);
    }
    return retArr;
  }

  private int[] getIntArray(List list)
  {
    int[] retArr = new int[list.size() * 2];
    ListIterator lit = list.listIterator();
    for (int ii = 0; lit.hasNext(); ii += 2)
    {
      Coordinate coord = (Coordinate) lit.next();
      retArr[ii] = (int) coord.y;
      retArr[ii + 1] = (int) coord.x;
    }
    return retArr;
  }

  public static boolean checkReverse(double[] sequence)
  {
    if (sequence.length < 4)
      return false;

    double p1y = sequence[0];
    double p1x = sequence[1];
    double p2y = sequence[sequence.length - 2];
    double p2x = sequence[sequence.length - 1];

    double dy = p2y - p1y;
    double dx = p2x - p1x;
    double atan = Math.atan2(dy, dx);
    if (atan < 0)
      atan += TwoPI;

    return atan > HalfPI && atan <= ThreePIhalf;
  }

}


Yours Rüdiger



 

-----Ursprüngliche Nachricht-----
Von: Cary O'Brien [mailto:cobrien_at_cornet.com]
Gesendet: Montag, 21. März 2005 21:52
An: openmap-users_at_bbn.com
Betreff: [OpenMap Users] Street labels

We have maps we are generating from the census data shape file (TIGER data). The maps look quite nice, but we need to add the street and feature names. Is there anything that will do this for us, like ArcView auto-label?

How are people handling labelling?

Thanks,

-- cary

cobrien_at_cornet.com

--
[To unsubscribe to this list send an email to "majdart_at_bbn.com"
with the following text in the BODY of the message "unsubscribe openmap-users"]
--
[To unsubscribe to this list send an email to "majdart_at_bbn.com"
with the following text in the BODY of the message "unsubscribe openmap-users"]
Received on Tue Mar 22 2005 - 02:54:36 EST

This archive was generated by hypermail 2.3.0 : Tue Mar 28 2017 - 23:25:06 EDT