1 /* 2 * Copyright (c) 2016 Vivid Solutions. 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.jts.operation.buffer; 13 14 /** 15 * A value class containing the parameters which 16 * specify how a buffer should be constructed. 17 * <p> 18 * The parameters allow control over: 19 * <ul> 20 * <li>Quadrant segments (accuracy of approximation for circular arcs) 21 * <li>End Cap style 22 * <li>Join style 23 * <li>Mitre limit 24 * <li>whether the buffer is single-sided 25 * </ul> 26 * 27 * @author Martin Davis 28 * 29 */ 30 public class BufferParameters 31 { 32 /** 33 * Specifies a round line buffer end cap style. 34 */ 35 public static final int CAP_ROUND = 1; 36 /** 37 * Specifies a flat line buffer end cap style. 38 */ 39 public static final int CAP_FLAT = 2; 40 /** 41 * Specifies a square line buffer end cap style. 42 */ 43 public static final int CAP_SQUARE = 3; 44 45 /** 46 * Specifies a round join style. 47 */ 48 public static final int JOIN_ROUND = 1; 49 /** 50 * Specifies a mitre join style. 51 */ 52 public static final int JOIN_MITRE = 2; 53 /** 54 * Specifies a bevel join style. 55 */ 56 public static final int JOIN_BEVEL = 3; 57 58 /** 59 * The default number of facets into which to divide a fillet of 90 degrees. 60 * A value of 8 gives less than 2% max error in the buffer distance. 61 * For a max error of < 1%, use QS = 12. 62 * For a max error of < 0.1%, use QS = 18. 63 */ 64 public static final int DEFAULT_QUADRANT_SEGMENTS = 8; 65 66 /** 67 * The default mitre limit 68 * Allows fairly pointy mitres. 69 */ 70 public static final double DEFAULT_MITRE_LIMIT = 5.0; 71 72 /** 73 * The default simplify factor 74 * Provides an accuracy of about 1%, which matches the accuracy of the default Quadrant Segments parameter. 75 */ 76 public static final double DEFAULT_SIMPLIFY_FACTOR = 0.01; 77 78 79 private int quadrantSegments = DEFAULT_QUADRANT_SEGMENTS; 80 private int endCapStyle = CAP_ROUND; 81 private int joinStyle = JOIN_ROUND; 82 private double mitreLimit = DEFAULT_MITRE_LIMIT; 83 private boolean isSingleSided = false; 84 private double simplifyFactor = DEFAULT_SIMPLIFY_FACTOR; 85 86 /** 87 * Creates a default set of parameters 88 * 89 */ BufferParameters()90 public BufferParameters() { 91 } 92 93 /** 94 * Creates a set of parameters with the 95 * given quadrantSegments value. 96 * 97 * @param quadrantSegments the number of quadrant segments to use 98 */ BufferParameters(int quadrantSegments)99 public BufferParameters(int quadrantSegments) 100 { 101 setQuadrantSegments(quadrantSegments); 102 } 103 104 /** 105 * Creates a set of parameters with the 106 * given quadrantSegments and endCapStyle values. 107 * 108 * @param quadrantSegments the number of quadrant segments to use 109 * @param endCapStyle the end cap style to use 110 */ BufferParameters(int quadrantSegments, int endCapStyle)111 public BufferParameters(int quadrantSegments, 112 int endCapStyle) 113 { 114 setQuadrantSegments(quadrantSegments); 115 setEndCapStyle(endCapStyle); 116 } 117 118 /** 119 * Creates a set of parameters with the 120 * given parameter values. 121 * 122 * @param quadrantSegments the number of quadrant segments to use 123 * @param endCapStyle the end cap style to use 124 * @param joinStyle the join style to use 125 * @param mitreLimit the mitre limit to use 126 */ BufferParameters(int quadrantSegments, int endCapStyle, int joinStyle, double mitreLimit)127 public BufferParameters(int quadrantSegments, 128 int endCapStyle, 129 int joinStyle, 130 double mitreLimit) 131 { 132 setQuadrantSegments(quadrantSegments); 133 setEndCapStyle(endCapStyle); 134 setJoinStyle(joinStyle); 135 setMitreLimit(mitreLimit); 136 } 137 138 /** 139 * Gets the number of quadrant segments which will be used 140 * 141 * @return the number of quadrant segments 142 */ getQuadrantSegments()143 public int getQuadrantSegments() 144 { 145 return quadrantSegments; 146 } 147 148 /** 149 * Sets the number of line segments used to approximate an angle fillet. 150 * <ul> 151 * <li>If <tt>quadSegs</tt> >= 1, joins are round, and <tt>quadSegs</tt> indicates the number of 152 * segments to use to approximate a quarter-circle. 153 * <li>If <tt>quadSegs</tt> = 0, joins are bevelled (flat) 154 * <li>If <tt>quadSegs</tt> < 0, joins are mitred, and the value of qs 155 * indicates the mitre ration limit as 156 * <pre> 157 * mitreLimit = |<tt>quadSegs</tt>| 158 * </pre> 159 * </ul> 160 * For round joins, <tt>quadSegs</tt> determines the maximum 161 * error in the approximation to the true buffer curve. 162 * The default value of 8 gives less than 2% max error in the buffer distance. 163 * For a max error of < 1%, use QS = 12. 164 * For a max error of < 0.1%, use QS = 18. 165 * The error is always less than the buffer distance 166 * (in other words, the computed buffer curve is always inside the true 167 * curve). 168 * 169 * @param quadSegs the number of segments in a fillet for a quadrant 170 */ setQuadrantSegments(int quadSegs)171 public void setQuadrantSegments(int quadSegs) 172 { 173 quadrantSegments = quadSegs; 174 175 /** 176 * Indicates how to construct fillets. 177 * If qs >= 1, fillet is round, and qs indicates number of 178 * segments to use to approximate a quarter-circle. 179 * If qs = 0, fillet is bevelled flat (i.e. no filleting is performed) 180 * If qs < 0, fillet is mitred, and absolute value of qs 181 * indicates maximum length of mitre according to 182 * 183 * mitreLimit = |qs| 184 */ 185 if (quadrantSegments == 0) 186 joinStyle = JOIN_BEVEL; 187 if (quadrantSegments < 0) { 188 joinStyle = JOIN_MITRE; 189 mitreLimit = Math.abs(quadrantSegments); 190 } 191 192 if (quadSegs <= 0) { 193 quadrantSegments = 1; 194 } 195 196 /** 197 * If join style was set by the quadSegs value, 198 * use the default for the actual quadrantSegments value. 199 */ 200 if (joinStyle != JOIN_ROUND) { 201 quadrantSegments = DEFAULT_QUADRANT_SEGMENTS; 202 } 203 } 204 205 /** 206 * Computes the maximum distance error due to a given level 207 * of approximation to a true arc. 208 * 209 * @param quadSegs the number of segments used to approximate a quarter-circle 210 * @return the error of approximation 211 */ bufferDistanceError(int quadSegs)212 public static double bufferDistanceError(int quadSegs) 213 { 214 double alpha = Math.PI / 2.0 / quadSegs; 215 return 1 - Math.cos(alpha / 2.0); 216 } 217 218 /** 219 * Gets the end cap style. 220 * 221 * @return the end cap style 222 */ getEndCapStyle()223 public int getEndCapStyle() 224 { 225 return endCapStyle; 226 } 227 228 /** 229 * Specifies the end cap style of the generated buffer. 230 * The styles supported are {@link #CAP_ROUND}, {@link #CAP_FLAT}, and {@link #CAP_SQUARE}. 231 * The default is CAP_ROUND. 232 * 233 * @param endCapStyle the end cap style to specify 234 */ setEndCapStyle(int endCapStyle)235 public void setEndCapStyle(int endCapStyle) 236 { 237 this.endCapStyle = endCapStyle; 238 } 239 240 /** 241 * Gets the join style 242 * 243 * @return the join style code 244 */ getJoinStyle()245 public int getJoinStyle() 246 { 247 return joinStyle; 248 } 249 250 /** 251 * Sets the join style for outside (reflex) corners between line segments. 252 * Allowable values are {@link #JOIN_ROUND} (which is the default), 253 * {@link #JOIN_MITRE} and {link JOIN_BEVEL}. 254 * 255 * @param joinStyle the code for the join style 256 */ setJoinStyle(int joinStyle)257 public void setJoinStyle(int joinStyle) 258 { 259 this.joinStyle = joinStyle; 260 } 261 262 /** 263 * Gets the mitre ratio limit. 264 * 265 * @return the limit value 266 */ getMitreLimit()267 public double getMitreLimit() 268 { 269 return mitreLimit; 270 } 271 272 /** 273 * Sets the limit on the mitre ratio used for very sharp corners. 274 * The mitre ratio is the ratio of the distance from the corner 275 * to the end of the mitred offset corner. 276 * When two line segments meet at a sharp angle, 277 * a miter join will extend far beyond the original geometry. 278 * (and in the extreme case will be infinitely far.) 279 * To prevent unreasonable geometry, the mitre limit 280 * allows controlling the maximum length of the join corner. 281 * Corners with a ratio which exceed the limit will be beveled. 282 * 283 * @param mitreLimit the mitre ratio limit 284 */ setMitreLimit(double mitreLimit)285 public void setMitreLimit(double mitreLimit) 286 { 287 this.mitreLimit = mitreLimit; 288 } 289 290 /** 291 * Sets whether the computed buffer should be single-sided. 292 * A single-sided buffer is constructed on only one side of each input line. 293 * <p> 294 * The side used is determined by the sign of the buffer distance: 295 * <ul> 296 * <li>a positive distance indicates the left-hand side 297 * <li>a negative distance indicates the right-hand side 298 * </ul> 299 * The single-sided buffer of point geometries is 300 * the same as the regular buffer. 301 * <p> 302 * The End Cap Style for single-sided buffers is 303 * always ignored, 304 * and forced to the equivalent of <tt>CAP_FLAT</tt>. 305 * 306 * @param isSingleSided true if a single-sided buffer should be constructed 307 */ setSingleSided(boolean isSingleSided)308 public void setSingleSided(boolean isSingleSided) 309 { 310 this.isSingleSided = isSingleSided; 311 } 312 313 /** 314 * Tests whether the buffer is to be generated on a single side only. 315 * 316 * @return true if the generated buffer is to be single-sided 317 */ isSingleSided()318 public boolean isSingleSided() { 319 return isSingleSided; 320 } 321 322 /** 323 * Gets the simplify factor. 324 * 325 * @return the simplify factor 326 */ getSimplifyFactor()327 public double getSimplifyFactor() { 328 return simplifyFactor; 329 } 330 331 /** 332 * Sets the factor used to determine the simplify distance tolerance 333 * for input simplification. 334 * Simplifying can increase the performance of computing buffers. 335 * Generally the simplify factor should be greater than 0. 336 * Values between 0.01 and .1 produce relatively good accuracy for the generate buffer. 337 * Larger values sacrifice accuracy in return for performance. 338 * 339 * @param simplifyFactor a value greater than or equal to zero. 340 */ setSimplifyFactor(double simplifyFactor)341 public void setSimplifyFactor(double simplifyFactor) 342 { 343 this.simplifyFactor = simplifyFactor < 0 ? 0 : simplifyFactor; 344 } 345 } 346