1 /*
2  * Copyright (c) 2019 Martin Davis.
3  *
4  * All rights reserved. This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * and Eclipse Distribution License v. 1.0 which accompanies this distribution.
7  * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v20.html
8  * and the Eclipse Distribution License is available at
9  *
10  * http://www.eclipse.org/org/documents/edl-v10.php.
11  */
12 package org.locationtech.jtstest.testbuilder.ui.style;
13 
14 import java.awt.Color;
15 import java.awt.Graphics2D;
16 
17 import org.locationtech.jts.geom.Coordinate;
18 import org.locationtech.jts.geom.Geometry;
19 import org.locationtech.jts.geom.LineString;
20 import org.locationtech.jts.linearref.LengthIndexedLine;
21 import org.locationtech.jts.operation.buffer.BufferParameters;
22 import org.locationtech.jts.operation.buffer.OffsetCurveBuilder;
23 import org.locationtech.jtstest.testbuilder.ui.ColorUtil;
24 import org.locationtech.jtstest.testbuilder.ui.Viewport;
25 
26 public class LayerStyle implements Style  {
27 
28   public static final int INIT_OFFSET_SIZE = 5;
29 
30   private BasicStyle geomStyle;
31   private StyleList decoratorStyle;
32   private VertexStyle vertexStyle;
33   private DataLabelStyle labelStyle;
34   private int fillType = Palette.TYPE_BASIC;
35 
36   private StyleGroup orientStyle;
37   private PolygonStructureStyle structureStyle;
38   private ArrowSegmentStyle segArrowStyle;
39   private ArrowLineEndStyle lineArrowStyle;
40   private CircleLineEndStyle lineCircleStyle;
41   private VertexLabelStyle vertexLabelStyle;
42   private boolean isOffsetLine;
43   private int offsetSize = INIT_OFFSET_SIZE;
44 
45   private CircleLineEndStyle startPointStyle;
46 
47   private CircleLineEndStyle endPointStyle;
48 
49   private StyleGroup endPointsStyle;
50 
51   private SegmentIndexStyle segIndexStyle;
52 
LayerStyle(BasicStyle geomStyle)53   public LayerStyle(BasicStyle geomStyle) {
54     this.geomStyle = geomStyle;
55     initDecorators(geomStyle);
56   }
57 
LayerStyle(BasicStyle geomStyle, StyleList decoratorStyle)58   public LayerStyle(BasicStyle geomStyle, StyleList decoratorStyle) {
59     this.geomStyle = geomStyle;
60     this.decoratorStyle = decoratorStyle;
61   }
62 
LayerStyle(LayerStyle layerStyle)63   public LayerStyle(LayerStyle layerStyle) {
64     this.geomStyle = layerStyle.geomStyle.copy();
65     initDecorators(geomStyle);
66     update(layerStyle);
67     isOffsetLine = layerStyle.isOffsetLine;
68     offsetSize = layerStyle.offsetSize;
69   }
70 
copy()71   public LayerStyle copy() {
72     return new LayerStyle(this);
73   }
74 
getGeomStyle()75   public BasicStyle getGeomStyle() {
76     return geomStyle;
77   }
78 
getDecoratorStyle()79   public StyleList getDecoratorStyle() {
80     return decoratorStyle;
81   }
82 
initDecorators(BasicStyle style)83   private void initDecorators(BasicStyle style)
84   {
85     vertexStyle = new VertexStyle(style.getLineColor());
86     vertexLabelStyle = new VertexLabelStyle(style.getLineColor());
87     labelStyle = new DataLabelStyle(ColorUtil.opaque(style.getLineColor().darker()));
88 
89     segArrowStyle = new ArrowSegmentStyle(ColorUtil.lighter(style.getLineColor(), 0.8));
90     lineArrowStyle = new ArrowLineEndStyle(ColorUtil.lighter(style.getLineColor(),0.5), false, true);
91     lineCircleStyle = new CircleLineEndStyle(ColorUtil.lighter(style.getLineColor(),0.5), 6, 8, true, true);
92     orientStyle = new StyleGroup(segArrowStyle, lineArrowStyle, lineCircleStyle);
93 
94     double endPtSize = 2 * vertexStyle.getSize();
95     startPointStyle = new CircleLineEndStyle(style.getLineColor(), endPtSize, true, true);
96     endPointStyle = new CircleLineEndStyle(style.getLineColor(), endPtSize, false, true);
97     endPointsStyle = new StyleGroup(startPointStyle, endPointStyle);
98 
99     structureStyle = new PolygonStructureStyle(ColorUtil.opaque(style.getLineColor()));
100     segIndexStyle = new SegmentIndexStyle(ColorUtil.opaque(style.getLineColor().darker()));
101 
102     // order is important here
103     StyleList styleList = new StyleList();
104     styleList.add(vertexLabelStyle);
105     styleList.add(vertexStyle);
106     styleList.add(endPointsStyle);
107     styleList.add(orientStyle);
108     styleList.add(structureStyle);
109     styleList.add(segIndexStyle);
110     styleList.add(labelStyle);
111 
112     styleList.setEnabled(endPointsStyle, false);
113     styleList.setEnabled(labelStyle, false);
114     styleList.setEnabled(orientStyle, false);
115     styleList.setEnabled(structureStyle, false);
116     styleList.setEnabled(segIndexStyle, false);
117     styleList.setEnabled(vertexLabelStyle, false);
118 
119     decoratorStyle = styleList;
120   }
121 
update(LayerStyle layerStyle)122   private void update(LayerStyle layerStyle) {
123     setStructure(layerStyle.isStructure());
124     setSegIndex(layerStyle.isSegIndex());
125     setOrientations(layerStyle.isOrientations());
126     setLabel(layerStyle.isLabel());
127     setLabelSize(layerStyle.getLabelSize());
128     setVertices(layerStyle.isVertices());
129     setVertexSize(layerStyle.getVertexSize());
130     setVertexColor(layerStyle.getVertexColor());
131     setVertexLabels(layerStyle.isVertexLabels());
132     setVertexSymbol(layerStyle.getVertexSymbol());
133     setEndpoints(layerStyle.isEndpoints());
134   }
135 
getFillType()136   public int getFillType() {
137     return fillType;
138   }
setFillType(int fillType)139   public void setFillType(int fillType) {
140     this.fillType = fillType;
141   }
142 
getVertexSymbol()143   public int getVertexSymbol() {
144     return vertexStyle.getSymbol();
145   }
setVertexSymbol(int sym)146   public void setVertexSymbol(int sym) {
147     vertexStyle.setSymbol(sym);
148   }
149 
setColor(Color color)150   public void setColor(Color color) {
151     segArrowStyle.setColor( ColorUtil.lighter(color,0.8) );
152     lineArrowStyle.setColor( ColorUtil.lighter(color,0.5) );
153     lineCircleStyle.setColor( ColorUtil.lighter(color,0.5) );
154   }
155 
setVertices(boolean show)156   public void setVertices(boolean show) {
157     decoratorStyle.setEnabled(vertexStyle, show);
158   }
159 
isVertices()160   public boolean isVertices() {
161     return decoratorStyle.isEnabled(vertexStyle);
162   }
163 
setEndpoints(boolean show)164   public void setEndpoints(boolean show) {
165     decoratorStyle.setEnabled(endPointsStyle, show);
166   }
167 
isEndpoints()168   public boolean isEndpoints() {
169     return decoratorStyle.isEnabled(endPointsStyle);
170   }
171 
getVertexSize()172   public int getVertexSize() {
173     return vertexStyle.getSize();
174   }
setVertexSize(int size)175   public void setVertexSize(int size) {
176     vertexStyle.setSize(size);
177     startPointStyle.setSize(2 * size);
178     endPointStyle.setSize(2 * size);
179   }
180 
getVertexColor()181   public Color getVertexColor() {
182     return vertexStyle.getColor();
183   }
setVertexColor(Color color)184   public void setVertexColor(Color color) {
185     vertexStyle.setColor(color);
186     vertexLabelStyle.setColor(color);
187     startPointStyle.setColor(color);
188     endPointStyle.setColor(color);
189   }
setVertexLabels(boolean show)190   public void setVertexLabels(boolean show) {
191     decoratorStyle.setEnabled(vertexLabelStyle, show);
192   }
isVertexLabels()193   public boolean isVertexLabels() {
194     return decoratorStyle.isEnabled(vertexLabelStyle);
195   }
196 
setLabel(boolean show)197   public void setLabel(boolean show) {
198     decoratorStyle.setEnabled(labelStyle, show);
199   }
200 
isLabel()201   public boolean isLabel() {
202     return decoratorStyle.isEnabled(labelStyle);
203   }
204 
getLabelSize()205   public int getLabelSize() {
206     return labelStyle.getSize();
207   }
setLabelSize(int size)208   public void setLabelSize(int size) {
209     labelStyle.setSize(size);
210   }
211 
getLabelColor()212   public Color getLabelColor() {
213     return labelStyle.getColor();
214   }
setLabelColor(Color color)215   public void setLabelColor(Color color) {
216     labelStyle.setColor(color);
217   }
218 
paint(Geometry geom, Viewport viewport, Graphics2D g)219   public void paint(Geometry geom, Viewport viewport, Graphics2D g) throws Exception {
220     Geometry transformGeom = transform(geom, viewport);
221     geomStyle.paint(transformGeom, viewport, g);
222     decoratorStyle.paint(transformGeom, viewport, g);
223   }
224 
transform(Geometry geom, Viewport viewport)225   private Geometry transform(Geometry geom, Viewport viewport) {
226     Geometry transformGeom = geom;
227     if (isOffsetLine && geom instanceof LineString) {
228       double offsetDistance = viewport.toModel(offsetSize);
229       transformGeom = offsetLine(geom, offsetDistance);
230       if (transformGeom != null) {
231         transformGeom.setUserData(geom.getUserData());
232       }
233     }
234     return transformGeom;
235   }
236 
setOffset(boolean show)237   public void setOffset(boolean show) {
238     isOffsetLine = show;
239   }
240 
isOffset()241   public boolean isOffset() {
242     return isOffsetLine;
243   }
244 
setOffsetSize(int offsetSize)245   public void setOffsetSize(int offsetSize) {
246     this.offsetSize = offsetSize;
247   }
248 
getOffsetSize()249   public int getOffsetSize() {
250     return offsetSize;
251    }
252 
setOrientations(boolean show)253   public void setOrientations(boolean show) {
254     decoratorStyle.setEnabled(orientStyle, show);
255   }
256 
isOrientations()257   public boolean isOrientations() {
258     return decoratorStyle.isEnabled(orientStyle);
259   }
260 
setStructure(boolean show)261   public void setStructure(boolean show) {
262     decoratorStyle.setEnabled(structureStyle, show);
263   }
264 
isStructure()265   public boolean isStructure() {
266     return decoratorStyle.isEnabled(structureStyle);
267   }
268 
setSegIndex(boolean show)269   public void setSegIndex(boolean show) {
270     decoratorStyle.setEnabled(segIndexStyle, show);
271   }
272 
isSegIndex()273   public boolean isSegIndex() {
274     return decoratorStyle.isEnabled(segIndexStyle);
275   }
276 
offsetLine(Geometry geom, double distance)277   static Geometry offsetLine(Geometry geom, double distance)
278   {
279     BufferParameters bufParams = new BufferParameters();
280     OffsetCurveBuilder ocb = new OffsetCurveBuilder(
281         geom.getFactory().getPrecisionModel(), bufParams
282         );
283     Coordinate[] pts = ocb.getOffsetCurve(geom.getCoordinates(), distance);
284     Geometry offsetLine = geom.getFactory().createLineString(pts);
285     Geometry trimLine = trimLine(offsetLine, Math.abs(distance * 1.5) );
286     return trimLine;
287   }
288 
trimLine(Geometry line, double distance)289   private static Geometry trimLine(Geometry line, double distance) {
290     double len = line.getLength();
291     if (len < 2 * distance) return line;
292     LengthIndexedLine indLine = new LengthIndexedLine(line);
293     return indLine.extractLine(distance, len - distance);
294   }
295 
296 
297 
298 
299 
300 }
301