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