/* * The JTS Topology Suite is a collection of Java classes that * implement the fundamental operations required to validate a given * geo-spatial data set to a known topological specification. * * Copyright (C) 2001 Vivid Solutions * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; 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.revolsys.geometry.test.old.perf.algorithm; import java.util.Iterator; import java.util.List; import com.revolsys.geometry.algorithm.RayCrossingCounter; import com.revolsys.geometry.algorithm.locate.PointOnGeometryLocator; import com.revolsys.geometry.index.SpatialIndex; import com.revolsys.geometry.index.chain.MonotoneChain; import com.revolsys.geometry.index.chain.MonotoneChainBuilder; import com.revolsys.geometry.index.chain.MonotoneChainSelectAction; import com.revolsys.geometry.index.strtree.STRtree; import com.revolsys.geometry.model.BoundingBox; import com.revolsys.geometry.model.Geometry; import com.revolsys.geometry.model.LineString; import com.revolsys.geometry.model.Location; import com.revolsys.geometry.model.Point; import com.revolsys.geometry.model.Polygonal; import com.revolsys.geometry.model.impl.BoundingBoxDoubleXY; import com.revolsys.geometry.model.segment.LineSegment; import com.revolsys.geometry.noding.BasicSegmentString; import com.revolsys.geometry.noding.SegmentString; class MCIndexedGeometry { private final SpatialIndex index = new STRtree(); public MCIndexedGeometry(final Geometry geom) { init(geom); } private void addLine(final LineString points) { final SegmentString segStr = new BasicSegmentString(points, null); final List<MonotoneChain> segChains = MonotoneChainBuilder.getChains(segStr.getPoints(), segStr); for (final MonotoneChain mc : segChains) { this.index.insertItem(mc.getEnvelope(), mc); } } private void init(final Geometry geom) { final List<LineString> lines = geom.getGeometryComponents(LineString.class); for (final LineString line : lines) { final LineString points = line; addLine(points); } } public List query(final BoundingBox searchEnv) { return this.index.getItems(searchEnv); } } /** * Determines the location of {@link Coordinates}s relative to * a {@link Polygonal} geometry, using indexing for efficiency. * This algorithm is suitable for use in cases where * many points will be tested against a given area. * * @author Martin Davis * */ public class MCIndexedPointInAreaLocator implements PointOnGeometryLocator { static class MCSegmentCounter extends MonotoneChainSelectAction { RayCrossingCounter rcc; public MCSegmentCounter(final RayCrossingCounter rcc) { this.rcc = rcc; } @Override public void select(final LineSegment ls) { this.rcc.countSegment(ls.getPoint(0), ls.getPoint(1)); } } private MCIndexedGeometry index; private final double maxXExtent; public MCIndexedPointInAreaLocator(final Geometry g) { if (!(g instanceof Polygonal)) { throw new IllegalArgumentException("Argument must be Polygonal"); } buildIndex(g); final BoundingBox env = g.getBoundingBox(); this.maxXExtent = env.getMaxX() + 1.0; } private void buildIndex(final Geometry g) { this.index = new MCIndexedGeometry(g); } private void countSegs(final RayCrossingCounter rcc, final BoundingBox rayEnv, final List monoChains, final MCSegmentCounter mcSegCounter) { for (final Iterator i = monoChains.iterator(); i.hasNext();) { final MonotoneChain mc = (MonotoneChain)i.next(); mc.select(rayEnv, mcSegCounter); // short-circuit if possible if (rcc.isOnSegment()) { return; } } } /** * Determines the {@link Location} of a point in an areal {@link Geometry}. * * @param p the point to test * @return the location of the point in the geometry */ @Override public Location locate(final Point p) { final RayCrossingCounter rcc = new RayCrossingCounter(p); final MCSegmentCounter mcSegCounter = new MCSegmentCounter(rcc); final BoundingBox rayEnv = new BoundingBoxDoubleXY(p.getX(), p.getY(), this.maxXExtent, p.getY()); final List mcs = this.index.query(rayEnv); countSegs(rcc, rayEnv, mcs, mcSegCounter); return rcc.getLocation(); } }