001: /*
002: * The Unified Mapping Platform (JUMP) is an extensible, interactive GUI
003: * for visualizing and manipulating spatial features with geometry and attributes.
004: *
005: * Copyright (C) 2003 Vivid Solutions
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License
009: * as published by the Free Software Foundation; either version 2
010: * of the License, or (at your option) any later version.
011: *
012: * This program is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
015: * GNU General Public License for more details.
016: *
017: * You should have received a copy of the GNU General Public License
018: * along with this program; if not, write to the Free Software
019: * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
020: *
021: * For more information, contact:
022: *
023: * Vivid Solutions
024: * Suite #1A
025: * 2328 Government Street
026: * Victoria BC V8T 5G5
027: * Canada
028: *
029: * (250)385-6040
030: * www.vividsolutions.com
031: */
032: package com.vividsolutions.jump.workbench.ui.renderer.style;
033:
034: import com.vividsolutions.jts.geom.Envelope;
035: import com.vividsolutions.jts.geom.Geometry;
036: import com.vividsolutions.jts.geom.GeometryCollection;
037: import com.vividsolutions.jts.geom.TopologyException;
038: import com.vividsolutions.jts.util.AssertionFailedException;
039:
040: import com.vividsolutions.jump.geom.EnvelopeUtil;
041: import com.vividsolutions.jump.workbench.ui.Viewport;
042:
043: import java.awt.*;
044: import java.awt.geom.GeneralPath;
045: import java.awt.geom.NoninvertibleTransformException;
046:
047: public class StyleUtil {
048: /**
049: * Smart enough to not fill LineStrings.
050: */
051: public static void paint(Geometry geometry, Graphics2D g,
052: Viewport viewport, boolean renderingFill,
053: Stroke fillStroke, Paint fillPaint, boolean renderingLine,
054: Stroke lineStroke, Color lineColor)
055: throws NoninvertibleTransformException {
056: if (geometry instanceof GeometryCollection) {
057: paintGeometryCollection((GeometryCollection) geometry, g,
058: viewport, renderingFill, fillStroke, fillPaint,
059: renderingLine, lineStroke, lineColor);
060:
061: return;
062: }
063:
064: Shape shape = toShape(geometry, viewport);
065: if (!(shape instanceof GeneralPath) && renderingFill) {
066: g.setStroke(fillStroke);
067: g.setPaint(fillPaint);
068: g.fill(shape);
069: }
070: if (renderingLine) {
071: g.setStroke(lineStroke);
072: g.setColor(lineColor);
073: g.draw(shape);
074: }
075: }
076:
077: private static void paintGeometryCollection(
078: GeometryCollection collection, Graphics2D g,
079: Viewport viewport, boolean renderingFill,
080: Stroke fillStroke, Paint fillPaint, boolean renderingLine,
081: Stroke lineStroke, Color lineColor)
082: throws NoninvertibleTransformException {
083: //For GeometryCollections, render each element separately. Otherwise,
084: //for example, if you pass in a GeometryCollection containing a ring and a
085: // disk, you cannot render them as such: if you use Graphics.fill, you'll get
086: //two disks, and if you use Graphics.draw, you'll get two rings. [Jon Aquino]
087: for (int i = 0; i < collection.getNumGeometries(); i++) {
088: paint(collection.getGeometryN(i), g, viewport,
089: renderingFill, fillStroke, fillPaint,
090: renderingLine, lineStroke, lineColor);
091: }
092: }
093:
094: private static Shape toShape(Geometry geometry, Viewport viewport)
095: throws NoninvertibleTransformException {
096: //At high magnifications, Java rendering can be sped up by clipping
097: //the Geometry to only that portion visible inside the viewport.
098: //Hence the code below. [Jon Aquino]
099: Envelope bufferedEnvelope = EnvelopeUtil.bufferByFraction(
100: viewport.getEnvelopeInModelCoordinates(), 0.05);
101: Geometry actualGeometry = geometry;
102: Envelope geomEnv = actualGeometry.getEnvelopeInternal();
103: if (!bufferedEnvelope.contains(geomEnv)) {
104: /**
105: * MD - letting Java2D do more clipping actually seems to be slower!
106: * So don't use following "optimization"
107: */
108: //if (isRatioLarge(bufferedEnvelope, geomEnv, 2)) {
109: actualGeometry = clipGeometry(geometry, bufferedEnvelope);
110: //System.out.println("cl");
111: //}
112: }
113: return viewport.getJava2DConverter().toShape(actualGeometry);
114: }
115:
116: /**
117: * Clipping a geometry using JTS produces higher quality results than letting Java2D do it.
118: * It may also be faster!
119: *
120: * @param geom
121: * @param env
122: * @return
123: */
124: private static Geometry clipGeometry(Geometry geom, Envelope env) {
125: try {
126: Geometry clipGeom = EnvelopeUtil.toGeometry(env)
127: .intersection(geom);
128: return clipGeom;
129: } catch (Exception e) {
130: //Can get a TopologyException if the Geometry is invalid. Eat it. [Jon Aquino]
131: //Can get an AssertionFailedException (unable to assign hole to a shell)
132: //at high magnifications. Eat it. [Jon Aquino]
133:
134: //Alvaro Zabala reports that we can get here with an
135: //IllegalArgumentException (points must form a closed linestring)
136: //for bad geometries. Eat it. [Jon Aquino]
137: }
138: return geom;
139: }
140:
141: private static boolean isRatioLarge(Envelope viewEnv,
142: Envelope geomEnv, double factor) {
143: if (isRatioLarge(viewEnv.getHeight(), geomEnv.getHeight(),
144: factor))
145: return true;
146: if (isRatioLarge(viewEnv.getWidth(), geomEnv.getWidth(), factor))
147: return true;
148: return false;
149: }
150:
151: private static boolean isRatioLarge(double winDim, double geomDim,
152: double factor) {
153: return (geomDim / winDim) < factor;
154: }
155: }
|