Class BufferParameters

  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    */
 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    */
 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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
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    */
318   public boolean isSingleSided() {
319     return isSingleSided;
320   }
321  
322   /**
323    * Gets the simplify factor.
324    * 
325    * @return the simplify factor
326    */
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    */
341   public void setSimplifyFactor(double simplifyFactor)
342   {
343     this.simplifyFactor = simplifyFactor < 0 ? 0 : simplifyFactor;
344   }
345 }
346