/* * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI * for visualizing and manipulating spatial features with geometry and attributes. * * Copyright (C) 2003 Vivid Solutions * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * * For more information, contact: * * Vivid Solutions * Suite #1A * 2328 Government Street * Victoria BC V8T 5G5 * Canada * * (250)385-6040 * www.vividsolutions.com */ package com.vividsolutions.jump.geom; import com.vividsolutions.jts.geom.*; import com.vividsolutions.jump.util.MathUtil; /** * Find a reasonable point at which to label a Geometry. * <p> * Algorithm is: * <ul> * <li>Find the intersections between the geometry and a line halfway * down the envelope * <li>Pick the midpoint of the largest intersection (the intersections * will be lines and points) * </ul> */ public class InteriorPointFinder { private GeometryFactory factory = new GeometryFactory(); //<<TODO:REFACTORING>> Move this class to JTS [Jon Aquino] public InteriorPointFinder() { } /** * Finds a reasonable point at which to label a Geometry. * @param geometry the geometry to analyze * @return the midpoint of the largest intersection between the geometry and * a line halfway down its envelope */ public Coordinate findPoint(Geometry geometry) { if (geometry.isEmpty()) { //Can't use geometry#getPoint because it returns null [Jon Aquino] return new Coordinate(0, 0); } if (geometry.getDimension() == 0) { //Points and multipoints [Jon Aquino] return geometry.getCoordinate(); } if (geometry instanceof GeometryCollection) { return findPoint(((GeometryCollection) geometry).getGeometryN(0)); } Geometry envelopeMiddle = envelopeMiddle(geometry); if (envelopeMiddle instanceof Point) { return envelopeMiddle.getCoordinate(); } Geometry intersections = envelopeMiddle.intersection(geometry); Geometry widestIntersection = widestGeometry(intersections); return centre(widestIntersection.getEnvelopeInternal()); } //@return if geometry is a collection, the widest sub-geometry; otherwise, //the geometry itself protected Geometry widestGeometry(Geometry geometry) { if (!(geometry instanceof GeometryCollection)) { return geometry; } return widestGeometry((GeometryCollection) geometry); } private Geometry widestGeometry(GeometryCollection gc) { if (gc.isEmpty()) { return gc; } Geometry widestGeometry = gc.getGeometryN(0); for (int i = 1; i < gc.getNumGeometries(); i++) { //Start at 1 if (gc.getGeometryN(i).getEnvelopeInternal().getWidth() > widestGeometry.getEnvelopeInternal() .getWidth()) { widestGeometry = gc.getGeometryN(i); } } return widestGeometry; } protected Geometry envelopeMiddle(Geometry geometry) { Envelope envelope = geometry.getEnvelopeInternal(); if (envelope.getWidth() == 0) { return factory.createPoint(centre(envelope)); } return factory.createLineString(new Coordinate[] { new Coordinate(envelope.getMinX(), MathUtil.avg(envelope.getMinY(), envelope.getMaxY())), new Coordinate(envelope.getMaxX(), MathUtil.avg(envelope.getMinY(), envelope.getMaxY())) }); } /** * Returns the centre-of-mass of the envelope. * @param envelope the envelope to analyze * @return the centre of the envelope */ public Coordinate centre(Envelope envelope) { //<<TODO:REFACTORING>> Move #avg from GUIUtilities to a core JCS util class [Jon Aquino] return new Coordinate(MathUtil.avg(envelope.getMinX(), envelope.getMaxX()), MathUtil.avg(envelope.getMinY(), envelope.getMaxY())); } }