// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/layer/mif/OMSubtraction.java,v $ // $RCSfile: OMSubtraction.java,v $ // $Revision: 1.4 $ // $Date: 2009/01/21 01:24:42 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.layer.mif; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Polygon; import java.awt.geom.Area; import java.awt.geom.GeneralPath; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import com.bbn.openmap.omGraphics.OMGraphicAdapter; import com.bbn.openmap.proj.Projection; /** * Defines a Region of a MIF file where when one region encloses another the * enclosed region is subtracted from the enclosing region in order to create a * hole Computationally this can be expensive to do on a complex layout like a * streetmap of city */ public class OMSubtraction extends OMGraphicAdapter implements Serializable { SubArea outer; // The outer polygon of this region transient Area area; // calculated List<SubArea> subs; // An array of the subtractions to make public OMSubtraction(double[] lat, double[] lon) { super(RENDERTYPE_LATLON, LINETYPE_UNKNOWN, DECLUTTERTYPE_NONE); outer = new SubArea(lat, lon); } boolean contains(double[] latp, double[] lonp) { if (outer.contains(latp, lonp)) { if (subs == null) { subs = new ArrayList<SubArea>(); } subs.add(new SubArea(latp, lonp)); return true; } return false; } public boolean generate(Projection proj) { if (proj == null) { System.err.println("OMText: null projection in generate!"); return false; } if (!outer.isPlotable(proj)) return false; area = outer.getArea(proj); if (subs != null) { for (SubArea sb : subs) { area.subtract(sb.getArea(proj)); } } setNeedToRegenerate(false); return true; } public synchronized void render(Graphics g) { if (getNeedToRegenerate()) return; if (area == null) return; Graphics2D g2 = (Graphics2D) g; g2.setPaint(getFillPaint()); g2.fill(area); } /** * Return the shortest distance from the line to an XY-point - not relevant * to this class. * * @param x X coordinate of the point. * @param y Y coordinate fo the point. * @return float always zero */ public float distance(double x, double y) { // return zero return 0.0f; } class SubArea implements Serializable { double[] lat; double[] lon; int[] x, y; int len; // We use this to ask if a point lies inside this area, // Polygon class is no good cos it needs ints GeneralPath gpath; SubArea(double[] lat, double[] lon) { this.lat = lat; this.lon = lon; len = lat.length; x = new int[len]; y = new int[len]; } Area getArea(Projection proj) { Point pt = new Point(); for (int i = 0; i < len; i++) { proj.forward(lat[i], lon[i], pt); x[i] = pt.x; y[i] = pt.y; } return new Area(new Polygon(x, y, len)); } boolean isPlotable(Projection proj) { return proj.isPlotable(lat[0], lon[0]); } boolean contains(double[] latp, double[] lonp) { if (gpath == null) { gpath = new GeneralPath(); for (int i = 0; i < len; i++) { if (i == 0) gpath.moveTo((float) lat[0], (float) lon[0]); gpath.lineTo((float) lat[i], (float) lon[i]); } gpath.closePath(); } int len = latp.length; for (int i = 0; i < len; i++) { if (gpath.contains(latp[i], lonp[i])) { return true; } } return false; } } }