All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.vividsolutions.jts.util.GeometricShapeFactory Maven / Gradle / Ivy

Go to download

The JTS Topology Suite is an API for modelling and manipulating 2-dimensional linear geometry. It provides numerous geometric predicates and functions. JTS conforms to the Simple Features Specification for SQL published by the Open GIS Consortium.

There is a newer version: 1.13
Show newest version
/*
 * 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.vividsolutions.jts.util;

import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.geom.util.AffineTransformation;

/**
 * Computes various kinds of common geometric shapes.
 * Provides various ways of specifying the location and extent
 * and rotations of the generated shapes,
 * as well as number of line segments used to form them.
 * 

* Example of usage: *

 *  GeometricShapeFactory gsf = new GeometricShapeFactory();
 *  gsf.setSize(100);
 *  gsf.setNumPoints(100);
 *  gsf.setBase(new Coordinate(100, 100));
 *  gsf.setRotation(0.5);
 *  Polygon rect = gsf.createRectangle();
 * 
* * @version 1.7 */ public class GeometricShapeFactory { protected GeometryFactory geomFact; protected PrecisionModel precModel = null; protected Dimensions dim = new Dimensions(); protected int nPts = 100; /** * Default is no rotation. */ protected double rotationAngle = 0.0; /** * Create a shape factory which will create shapes using the default * {@link GeometryFactory}. */ public GeometricShapeFactory() { this(new GeometryFactory()); } /** * Create a shape factory which will create shapes using the given * {@link GeometryFactory}. * * @param geomFact the factory to use */ public GeometricShapeFactory(GeometryFactory geomFact) { this.geomFact = geomFact; precModel = geomFact.getPrecisionModel(); } public void setEnvelope(Envelope env) { dim.setEnvelope(env); } /** * Sets the location of the shape by specifying the base coordinate * (which in most cases is the * lower left point of the envelope containing the shape). * * @param base the base coordinate of the shape */ public void setBase(Coordinate base) { dim.setBase(base); } /** * Sets the location of the shape by specifying the centre of * the shape's bounding box * * @param centre the centre coordinate of the shape */ public void setCentre(Coordinate centre) { dim.setCentre(centre); } /** * Sets the total number of points in the created {@link Geometry}. * The created geometry will have no more than this number of points, * unless more are needed to create a valid geometry. */ public void setNumPoints(int nPts) { this.nPts = nPts; } /** * Sets the size of the extent of the shape in both x and y directions. * * @param size the size of the shape's extent */ public void setSize(double size) { dim.setSize(size); } /** * Sets the width of the shape. * * @param width the width of the shape */ public void setWidth(double width) { dim.setWidth(width); } /** * Sets the height of the shape. * * @param height the height of the shape */ public void setHeight(double height) { dim.setHeight(height); } /** * Sets the rotation angle to use for the shape. * The rotation is applied relative to the centre of the shape. * * @param radians the rotation angle in radians. */ public void setRotation(double radians) { rotationAngle = radians; } protected Geometry rotate(Geometry geom) { if (rotationAngle != 0.0) { AffineTransformation trans = AffineTransformation.rotationInstance(rotationAngle, dim.getCentre().x, dim.getCentre().y); geom.apply(trans); } return geom; } /** * Creates a rectangular {@link Polygon}. * * @return a rectangular Polygon * */ public Polygon createRectangle() { int i; int ipt = 0; int nSide = nPts / 4; if (nSide < 1) nSide = 1; double XsegLen = dim.getEnvelope().getWidth() / nSide; double YsegLen = dim.getEnvelope().getHeight() / nSide; Coordinate[] pts = new Coordinate[4 * nSide + 1]; Envelope env = dim.getEnvelope(); //double maxx = env.getMinX() + nSide * XsegLen; //double maxy = env.getMinY() + nSide * XsegLen; for (i = 0; i < nSide; i++) { double x = env.getMinX() + i * XsegLen; double y = env.getMinY(); pts[ipt++] = coord(x, y); } for (i = 0; i < nSide; i++) { double x = env.getMaxX(); double y = env.getMinY() + i * YsegLen; pts[ipt++] = coord(x, y); } for (i = 0; i < nSide; i++) { double x = env.getMaxX() - i * XsegLen; double y = env.getMaxY(); pts[ipt++] = coord(x, y); } for (i = 0; i < nSide; i++) { double x = env.getMinX(); double y = env.getMaxY() - i * YsegLen; pts[ipt++] = coord(x, y); } pts[ipt++] = new Coordinate(pts[0]); LinearRing ring = geomFact.createLinearRing(pts); Polygon poly = geomFact.createPolygon(ring, null); return (Polygon) rotate(poly); } //* @deprecated use {@link createEllipse} instead /** * Creates a circular or elliptical {@link Polygon}. * * @return a circle or ellipse */ public Polygon createCircle() { return createEllipse(); } /** * Creates an elliptical {@link Polygon}. * If the supplied envelope is square the * result will be a circle. * * @return an ellipse or circle */ public Polygon createEllipse() { Envelope env = dim.getEnvelope(); double xRadius = env.getWidth() / 2.0; double yRadius = env.getHeight() / 2.0; double centreX = env.getMinX() + xRadius; double centreY = env.getMinY() + yRadius; Coordinate[] pts = new Coordinate[nPts + 1]; int iPt = 0; for (int i = 0; i < nPts; i++) { double ang = i * (2 * Math.PI / nPts); double x = xRadius * Math.cos(ang) + centreX; double y = yRadius * Math.sin(ang) + centreY; pts[iPt++] = coord(x, y); } pts[iPt] = new Coordinate(pts[0]); LinearRing ring = geomFact.createLinearRing(pts); Polygon poly = geomFact.createPolygon(ring, null); return (Polygon) rotate(poly); } /** * Creates a squircular {@link Polygon}. * * @return a squircle */ public Polygon createSquircle() /** * Creates a squircular {@link Polygon}. * * @return a squircle */ { return createSupercircle(4); } /** * Creates a supercircular {@link Polygon} * of a given positive power. * * @return a supercircle */ public Polygon createSupercircle(double power) { double recipPow = 1.0 / power; double radius = dim.getMinSize() / 2; Coordinate centre = dim.getCentre(); double r4 = Math.pow(radius, power); double y0 = radius; double xyInt = Math.pow(r4 / 2, recipPow); int nSegsInOct = nPts / 8; int totPts = nSegsInOct * 8 + 1; Coordinate[] pts = new Coordinate[totPts]; double xInc = xyInt / nSegsInOct; for (int i = 0; i <= nSegsInOct; i++) { double x = 0.0; double y = y0; if (i != 0) { x = xInc * i; double x4 = Math.pow(x, power); y = Math.pow(r4 - x4, recipPow); } pts[i] = coordTrans(x, y, centre); pts[2 * nSegsInOct - i] = coordTrans(y, x, centre); pts[2 * nSegsInOct + i] = coordTrans(y, -x, centre); pts[4 * nSegsInOct - i] = coordTrans(x, -y, centre); pts[4 * nSegsInOct + i] = coordTrans(-x, -y, centre); pts[6 * nSegsInOct - i] = coordTrans(-y, -x, centre); pts[6 * nSegsInOct + i] = coordTrans(-y, x, centre); pts[8 * nSegsInOct - i] = coordTrans(-x, y, centre); } pts[pts.length-1] = new Coordinate(pts[0]); LinearRing ring = geomFact.createLinearRing(pts); Polygon poly = geomFact.createPolygon(ring, null); return (Polygon) rotate(poly); } /** * Creates an elliptical arc, as a {@link LineString}. * The arc is always created in a counter-clockwise direction. * This can easily be reversed if required by using * {#link LineString.reverse()} * * @param startAng start angle in radians * @param angExtent size of angle in radians * @return an elliptical arc */ public LineString createArc( double startAng, double angExtent) { Envelope env = dim.getEnvelope(); double xRadius = env.getWidth() / 2.0; double yRadius = env.getHeight() / 2.0; double centreX = env.getMinX() + xRadius; double centreY = env.getMinY() + yRadius; double angSize = angExtent; if (angSize <= 0.0 || angSize > 2 * Math.PI) angSize = 2 * Math.PI; double angInc = angSize / (nPts - 1); Coordinate[] pts = new Coordinate[nPts]; int iPt = 0; for (int i = 0; i < nPts; i++) { double ang = startAng + i * angInc; double x = xRadius * Math.cos(ang) + centreX; double y = yRadius * Math.sin(ang) + centreY; pts[iPt++] = coord(x, y); } LineString line = geomFact.createLineString(pts); return (LineString) rotate(line); } /** * Creates an elliptical arc polygon. * The polygon is formed from the specified arc of an ellipse * and the two radii connecting the endpoints to the centre of the ellipse. * * @param startAng start angle in radians * @param angExtent size of angle in radians * @return an elliptical arc polygon */ public Polygon createArcPolygon(double startAng, double angExtent) { Envelope env = dim.getEnvelope(); double xRadius = env.getWidth() / 2.0; double yRadius = env.getHeight() / 2.0; double centreX = env.getMinX() + xRadius; double centreY = env.getMinY() + yRadius; double angSize = angExtent; if (angSize <= 0.0 || angSize > 2 * Math.PI) angSize = 2 * Math.PI; double angInc = angSize / (nPts - 1); // double check = angInc * nPts; // double checkEndAng = startAng + check; Coordinate[] pts = new Coordinate[nPts + 2]; int iPt = 0; pts[iPt++] = coord(centreX, centreY); for (int i = 0; i < nPts; i++) { double ang = startAng + angInc * i; double x = xRadius * Math.cos(ang) + centreX; double y = yRadius * Math.sin(ang) + centreY; pts[iPt++] = coord(x, y); } pts[iPt++] = coord(centreX, centreY); LinearRing ring = geomFact.createLinearRing(pts); Polygon poly = geomFact.createPolygon(ring, null); return (Polygon) rotate(poly); } protected Coordinate coord(double x, double y) { Coordinate pt = new Coordinate(x, y); precModel.makePrecise(pt); return pt; } protected Coordinate coordTrans(double x, double y, Coordinate trans) { return coord(x + trans.x, y + trans.y); } protected class Dimensions { public Coordinate base; public Coordinate centre; public double width; public double height; public void setBase(Coordinate base) { this.base = base; } public Coordinate getBase() { return base; } public void setCentre(Coordinate centre) { this.centre = centre; } public Coordinate getCentre() { return centre; } public void setSize(double size) { height = size; width = size; } public double getMinSize() { return Math.min(width, height); } public void setWidth(double width) { this.width = width; } public double getWidth() { return width; } public double getHeight() { return height; } public void setHeight(double height) { this.height = height; } public void setEnvelope(Envelope env) { this.width = env.getWidth(); this.height = env.getHeight(); this.base = new Coordinate(env.getMinX(), env.getMinY()); this.centre = new Coordinate(env.centre()); } public Envelope getEnvelope() { if (base != null) { return new Envelope(base.x, base.x + width, base.y, base.y + height); } if (centre != null) { return new Envelope(centre.x - width/2, centre.x + width/2, centre.y - height/2, centre.y + height/2); } return new Envelope(0, width, 0, height); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy