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 &lt; 1%, use QS = 12.
62    * For a max error of &lt; 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> &gt;= 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> &lt; 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 &lt; 1%, use QS = 12.
164    * For a max error of &lt; 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