View Javadoc

1   /**
2    * File: 	CirculinearCurve2DUtils.java
3    * Project: javaGeom
4    * 
5    * Distributed under the LGPL License.
6    *
7    * Created: 16 mai 09
8    */
9   package math.geom2d.circulinear;
10  
11  import static java.lang.Math.PI;
12  
13  import java.util.ArrayList;
14  import java.util.Collection;
15  import java.util.Iterator;
16  import java.util.TreeMap;
17  import java.util.TreeSet;
18  
19  import math.geom2d.Angle2D;
20  import math.geom2d.Point2D;
21  import math.geom2d.Shape2D;
22  import math.geom2d.Vector2D;
23  import math.geom2d.conic.Circle2D;
24  import math.geom2d.conic.CircleArc2D;
25  import math.geom2d.conic.CircularShape2D;
26  import math.geom2d.curve.ContinuousCurve2D;
27  import math.geom2d.curve.Curve2D;
28  import math.geom2d.curve.Curve2DUtils;
29  import math.geom2d.curve.CurveSet2D;
30  import math.geom2d.curve.SmoothCurve2D;
31  import math.geom2d.line.LinearShape2D;
32  import math.geom2d.point.PointSet2D;
33  
34  
35  /**
36   * Some utilities for working with circulinear curves.
37   * @author dlegland
38   *
39   */
40  public class CirculinearCurve2DUtils {
41      
42  	/**
43  	 * Converts a curve to a circulinear curve, by concatenating all elements
44  	 * of the curve to the appropriate circulinear curve type. If the curve
45  	 * contains onr or more non-circulinear smooth curve, a 
46  	 * NonCirculinearClassException is thrown.
47  	 */
48  	public static CirculinearCurve2D convert(Curve2D curve) {
49  		// first check type, to avoid unnecessary computations
50  		if (curve instanceof CirculinearCurve2D)
51  			return (CirculinearCurve2D) curve;
52  		
53  		// If the curve is continuous, creates a CirculinearContinuousCurve2D
54  		if (curve instanceof ContinuousCurve2D) {
55  			// extract smooth pieces
56  			ContinuousCurve2D continuous = (ContinuousCurve2D) curve;
57  			Collection<? extends SmoothCurve2D> smoothPieces = 
58  				continuous.getSmoothPieces();
59  			
60  			// prepare array of elements
61  			ArrayList<CirculinearElement2D> elements = 
62  				new ArrayList<CirculinearElement2D>(smoothPieces.size());
63  			
64  			// class cast for each element, or throw an exception
65  			for (SmoothCurve2D smooth : smoothPieces) {
66  				if (smooth instanceof CirculinearElement2D)
67  					elements.add((CirculinearElement2D) smooth);
68  				else
69  					throw new NonCirculinearClassException(smooth);
70  			}
71  			
72  			// create the resulting CirculinearContinuousCurve2D
73  			return new PolyCirculinearCurve2D<CirculinearElement2D>(elements);
74  		}
75  		
76  		// If the curve is continuous, creates a CirculinearContinuousCurve2D
77  		if (curve instanceof CurveSet2D) {
78  			// extract smooth pieces
79  			CurveSet2D<?> set = (CurveSet2D<?>) curve;
80  			Collection<? extends ContinuousCurve2D> continuousCurves = 
81  				set.getContinuousCurves();
82  			
83  			// prepare array of elements
84  			ArrayList<CirculinearContinuousCurve2D> curves = 
85  				new ArrayList<CirculinearContinuousCurve2D>(
86  						continuousCurves.size());
87  			
88  			// class cast for each element, or throw an exception
89  			for (ContinuousCurve2D continuous : continuousCurves) {
90  				if (continuous instanceof CirculinearContinuousCurve2D)
91  					curves.add((CirculinearContinuousCurve2D) continuous);
92  				else
93  					curves.add((CirculinearContinuousCurve2D) convert(continuous));
94  			}
95  			
96  			// create the resulting CirculinearContinuousCurve2D
97  			return new CirculinearCurveSet2D<CirculinearContinuousCurve2D>(curves);
98  		}
99  		
100 		return null;
101 	}
102 	
103 	/* (non-Javadoc)
104 	 * @see math.geom2d.circulinear.CirculinearCurve2D#getLength(double)
105 	 */
106 	public static double getLength(
107 			CurveSet2D<? extends CirculinearCurve2D> curve, 
108 			double pos) {
109 		//init
110 		double length = 0;
111 		
112 		// add length of each curve before current curve
113 		int index = curve.getCurveIndex(pos);
114 		for(int i=0; i<index; i++)
115 			length += curve.getCurve(i).getLength();
116 		
117 		// add portion of length for last curve
118 		if(index<curve.getCurveNumber()) {
119 			double pos2 = curve.getLocalPosition(pos-2*index);
120 			length += curve.getCurve(index).getLength(pos2);
121 		}
122 		
123 		// return result
124 		return length;
125 	}
126 
127 	/* (non-Javadoc)
128 	 * @see math.geom2d.circulinear.CirculinearCurve2D#getPosition(double)
129 	 */
130 	public static double getPosition(
131 			CurveSet2D<? extends CirculinearCurve2D> curveSet,
132 			double length) {
133 		
134 		// position to compute
135 		double pos = 0;
136 		
137 		// index of current curve
138 		int index = 0;
139 		
140 		// cumulative length
141 		double cumLength = getLength(curveSet, curveSet.getT0());
142 		
143 		// iterate on all curves
144 		for(CirculinearCurve2D curve : curveSet.getCurves()) {
145 			// length of current curve
146 			double curveLength = curve.getLength();
147 			
148 			// add either 2, or fraction of length
149 			if(cumLength+curveLength<length) {
150 				cumLength += curveLength;
151 				index ++;
152 			} else {
153 				// add local position on current curve
154 				double pos2 = curve.getPosition(length-cumLength);
155 				pos = curveSet.getGlobalPosition(index, pos2);
156 				break;
157 			}			
158 		}
159 		
160 		// return the result
161 		return pos;
162 	}
163 
164 	public static CirculinearCurve2D createParallel(
165 			CirculinearCurve2D curve, double dist) {
166 		
167 		// case of a continuous curve -> call specialized method
168 		if (curve instanceof CirculinearContinuousCurve2D) {
169 			return createContinuousParallel(
170 					(CirculinearContinuousCurve2D)curve, dist);
171 		} 
172 		
173 		// Create array for storing result
174 		CirculinearCurveSet2D<CirculinearContinuousCurve2D> parallel =
175 			new CirculinearCurveSet2D<CirculinearContinuousCurve2D>();
176 		
177 		// compute parallel of each continuous part, and add it to the result
178 		for(CirculinearContinuousCurve2D continuous : 
179 			curve.getContinuousCurves()){
180 			CirculinearContinuousCurve2D contParallel = 
181 				createContinuousParallel(continuous, dist);
182 			if(contParallel!=null)
183 				parallel.addCurve(contParallel);
184 		}
185 		
186 		// return the set of parallel curves
187 		return parallel;
188 	}
189     
190 	
191 	public static CirculinearContinuousCurve2D createContinuousParallel(
192 			CirculinearContinuousCurve2D curve, double dist) {
193 		
194 		// For circulinear elements, getParallel() is already implemented
195 		if (curve instanceof CirculinearElement2D) {
196 			return (CirculinearElement2D)((CirculinearElement2D)curve).getParallel(dist);
197 		} 
198 
199 		// extract collection of circulinear elements
200 		Collection<? extends CirculinearElement2D> elements = 
201 			curve.getSmoothPieces();
202 		Iterator<? extends CirculinearElement2D> iterator = 
203 			elements.iterator();
204 
205 		// previous curve
206 		CirculinearElement2D previous = null;
207 		CirculinearElement2D current = null;
208 
209 		// create array for storing result
210 		PolyCirculinearCurve2D<CirculinearContinuousCurve2D> parallel = 
211 			new PolyCirculinearCurve2D<CirculinearContinuousCurve2D> ();
212 
213 		// check if curve is empty
214 		if(!iterator.hasNext())
215 			return parallel;
216 
217 		// add parallel to the first curve
218 		previous = iterator.next();
219 		CirculinearElement2D elementParallel = (CirculinearElement2D)previous.getParallel(dist);
220 		parallel.addCurve(elementParallel);
221 
222 		// iterate on smooth pieces
223 		while(iterator.hasNext()){
224 			// get current curve
225 			current = iterator.next();
226 
227 			// add circle arc between the two curve elements
228 			addCircularJunction(parallel, previous, current, dist);
229 			
230 			// add parallel to current curve
231 			parallel.addCurve((CirculinearElement2D)current.getParallel(dist));
232 
233 			// prepare for next piece
234 			previous = current;
235 		}
236 
237 		// Add circle arc to close the parallel curve
238 		if(curve.isClosed()) {
239 			current = elements.iterator().next();
240 			addCircularJunction(parallel, previous, current, dist);
241 			parallel.setClosed(true);
242 		}
243 
244 		return parallel;
245 	}
246 	
247 	private static void addCircularJunction(
248 			PolyCirculinearCurve2D<CirculinearContinuousCurve2D> parallel,
249 			CirculinearElement2D previous, 
250 			CirculinearElement2D current, double dist) {		
251 		// center of circle arc
252 		Point2D center = current.getFirstPoint();
253 
254 		// compute tangents to each portion
255 		Vector2D vp = previous.getTangent(previous.getT1());
256 		Vector2D vc = current.getTangent(current.getT0());
257 
258 		// compute angles
259 		double startAngle, endAngle;
260 		if(dist>0) {
261 			startAngle = vp.getAngle() - PI/2;
262 			endAngle = vc.getAngle() - PI/2;
263 		} else {
264 			startAngle = vp.getAngle() + PI/2;
265 			endAngle = vc.getAngle() + PI/2;
266 		}
267 		
268 		// format angles to stay between 0 and 2*PI
269 		startAngle = Angle2D.formatAngle(startAngle);
270 		endAngle = Angle2D.formatAngle(endAngle);
271 		
272 		// compute angle difference, in absolute value
273 		double diffAngle = endAngle-startAngle;
274 		diffAngle = Math.min(diffAngle, 2*PI-diffAngle);
275 		
276 		// If the angle difference is too small, we consider the two curves
277 		// touch at their extremities
278 		if(Math.abs(diffAngle)<1e-10)
279 			return;
280 		
281 		// otherwise add a circle arc to the polycurve
282 		parallel.addCurve(new CircleArc2D(
283 				center, Math.abs(dist), startAngle, endAngle, dist>0));
284 	}
285 	
286 	/**
287 	 * Compute intersection point of a single curve, by iterating on pair of 
288 	 * Circulinear elements composing the curve.
289 	 * @return the set of self-intersection points
290 	 */
291 	public static Collection<Point2D> findSelfIntersections(
292 			CirculinearCurve2D curve) {
293 		
294 		// create array of circulinear elements
295 		ArrayList<CirculinearElement2D> elements = 
296 			new ArrayList<CirculinearElement2D>();
297 		
298 		// extract all circulinear elements of the curve
299 		for(CirculinearContinuousCurve2D cont : curve.getContinuousCurves())
300 			elements.addAll(cont.getSmoothPieces());
301 		
302 		// create array for storing result
303 		ArrayList<Point2D> result = new ArrayList<Point2D>(0);
304 		
305 		// iterate on each couple of elements
306 		int n = elements.size();
307 		for(int i=0; i<n-1; i++) {
308 			CirculinearElement2D elem1 = elements.get(i);
309 			for(int j=i; j<n; j++) {
310 				CirculinearElement2D elem2 = elements.get(j);
311 				// iterate on intersection between consecutive elements
312 				for(Point2D inter : findIntersections(elem1, elem2)) {
313 					// do not keep extremities
314 					if(inter.equals(elem1.getLastPoint()) &&
315 							inter.equals(elem2.getFirstPoint())) continue;
316 					if(inter.equals(elem1.getFirstPoint()) &&
317 							inter.equals(elem2.getLastPoint())) continue;
318 					// add the intersection if we keep it
319 					result.add(inter);
320 				}
321 			}
322 		}
323 		
324 		// return the set of intersections
325 		return result;
326 	}
327 
328 	public static double [][] locateSelfIntersections(
329 			CurveSet2D<? extends CirculinearElement2D> curve) {
330 		
331 		// create array for storing result
332 		ArrayList<Double> list1 = new ArrayList<Double>(0);
333 		ArrayList<Double> list2 = new ArrayList<Double>(0);
334 		
335 		// iterate on each couple of elements
336 		int n = curve.getCurveNumber();
337 		for(int i=0; i<n-1; i++) {
338 			CirculinearElement2D elem1 = curve.getCurve(i);
339 			for(int j=i+1; j<n; j++) {
340 				CirculinearElement2D elem2 = curve.getCurve(j);
341 				// iterate on intersection between consecutive elements
342 				for(Point2D inter : findIntersections(elem1, elem2)) {
343 					// do not keep extremities
344 					if(!Double.isInfinite(elem1.getT1())&&!Double.isInfinite(elem2.getT0()))
345 						if(inter.equals(elem1.getLastPoint()) &&
346 								inter.equals(elem2.getFirstPoint())) continue;
347 					if(!Double.isInfinite(elem1.getT0())&&!Double.isInfinite(elem2.getT1()))
348 						if(inter.equals(elem1.getFirstPoint()) &&
349 							inter.equals(elem2.getLastPoint())) continue;
350 					
351 					// add the intersection if we keep it
352 					list1.add(2*i + Curve2DUtils.toUnitSegment(
353 							elem1.getPosition(inter),
354 							elem1.getT0(), elem1.getT1()));
355 					list2.add(2*j + Curve2DUtils.toUnitSegment(
356 							elem2.getPosition(inter), 
357 							elem2.getT0(), elem2.getT1()));
358 				}
359 			}
360 		}
361 		
362 		// convert the 2 lists into a n*2 array
363 		int np = list1.size(); 
364 		double[][] result = new double[np][2];
365 		for(int i=0; i<np; i++){
366 			result[i][0] = list1.get(i);
367 			result[i][1] = list2.get(i);
368 		}
369 		
370 		// return the array of positions
371 		return result;
372 	}
373 	
374 	public static Collection<Point2D> findIntersections(
375 			CirculinearCurve2D curve1, CirculinearCurve2D curve2) {
376 		
377 		// create array of circulinear elements
378 		ArrayList<CirculinearElement2D> elements1 =
379 			new ArrayList<CirculinearElement2D>();
380 		ArrayList<CirculinearElement2D> elements2 = 
381 			new ArrayList<CirculinearElement2D>();
382 		
383 		// extract all circulinear elements of the curve
384 		for(CirculinearContinuousCurve2D cont : curve1.getContinuousCurves())
385 			elements1.addAll(cont.getSmoothPieces());
386 		for(CirculinearContinuousCurve2D cont : curve2.getContinuousCurves())
387 			elements2.addAll(cont.getSmoothPieces());
388 		
389 		// create array for storing result
390 		ArrayList<Point2D> result = new ArrayList<Point2D>(0);
391 		
392 		// iterate on each couple of elements
393 		int n1 = elements1.size();
394 		int n2 = elements2.size();
395 		for(int i=0; i<n1; i++) {
396 			CirculinearElement2D elem1 = elements1.get(i);
397 			for(int j=0; j<n2; j++) {
398 				CirculinearElement2D elem2 = elements2.get(j);
399 				// iterate on intersection between consecutive elements
400 				for(Point2D inter : findIntersections(elem1, elem2)) {
401 					// add the intersection if we keep it
402 					result.add(inter);
403 				}
404 			}
405 		}
406 		
407 		// return the set of intersections
408 		return result;
409 	}
410 	
411 	/**
412 	 * Locate intersection points of two curves. The result is a N-by-2 array
413 	 * of double, where N is the number of intersections. For each row, the
414 	 * first element is the position on the first curve, and the second
415 	 * element is the position on the second curve.
416 	 */
417 	public static double[][] locateIntersections(
418 			CirculinearCurve2D curve1, CirculinearCurve2D curve2) {
419 		
420 		// create array for storing result
421 		ArrayList<Double> list1 = new ArrayList<Double>(0);
422 		ArrayList<Double> list2 = new ArrayList<Double>(0);
423 
424 		// create array of circulinear elements
425 		ArrayList<CirculinearElement2D> elements1 = 
426 			new ArrayList<CirculinearElement2D>();
427 		ArrayList<CirculinearElement2D> elements2 = 
428 			new ArrayList<CirculinearElement2D>();
429 		
430 		// extract all circulinear elements of the curve
431 		for(CirculinearContinuousCurve2D cont : curve1.getContinuousCurves())
432 			elements1.addAll(cont.getSmoothPieces());
433 		for(CirculinearContinuousCurve2D cont : curve2.getContinuousCurves())
434 			elements2.addAll(cont.getSmoothPieces());
435 		
436 		// iterate on each couple of elements
437 		int n1 = elements1.size();
438 		int n2 = elements2.size();
439 		for(int i=0; i<n1; i++) {
440 			CirculinearElement2D elem1 = elements1.get(i);
441 			for(int j=0; j<n2; j++) {
442 				CirculinearElement2D elem2 = elements2.get(j);
443 				// iterate on intersection between consecutive elements
444 				for(Point2D inter : findIntersections(elem1, elem2)) {
445 					// add the intersection if we keep it
446 					list1.add(curve1.getPosition(inter));
447 					list2.add(curve2.getPosition(inter));
448 				}
449 			}
450 		}
451 		
452 		// convert the 2 lists into a n*2 array
453 		int np = list1.size(); 
454 		double[][] result = new double[np][2];
455 		for(int i=0; i<np; i++){
456 			result[i][0] = list1.get(i);
457 			result[i][1] = list2.get(i);
458 		}
459 		
460 		// return the array of positions
461 		return result;
462 	}
463 	
464 	/**
465 	 * Compute the intersections, if they exist, of two circulinear elements.
466 	 */
467 	public static Collection<Point2D> findIntersections(
468 			CirculinearElement2D elem1, 
469 			CirculinearElement2D elem2) {
470 		
471 		// First try to use linear shape methods
472 		if(elem1 instanceof LinearShape2D) {
473 			return elem2.getIntersections((LinearShape2D) elem1);
474 		}		
475 		if(elem2 instanceof LinearShape2D) {
476 			return elem1.getIntersections((LinearShape2D) elem2);
477 		}
478 		
479 		// From now, both elem1 and elem2 are instances of CircleShape2D
480 		// It is therefore possible to extract support circles
481 		Circle2D circ1 = ((CircularShape2D) elem1).getSupportingCircle();
482 		Circle2D circ2 = ((CircularShape2D) elem2).getSupportingCircle();
483 		
484 		// create array for storing result (max 2 possible intersections)
485 		ArrayList<Point2D> pts = new ArrayList<Point2D>(2);
486 		
487 		// for each of the circle intersections, check if they belong to
488 		// both elements
489 		for(Point2D inter : Circle2D.getIntersections(circ1, circ2)) {
490 			if(elem1.contains(inter) && elem2.contains(inter))
491 				pts.add(inter);
492 		}
493 		
494 		// return found intersections
495 		return pts;
496 	}
497 	
498 	/**
499 	 * Split a continuous curve which self-intersects into a set of continuous
500 	 * circulinear curves which do not self-intersect.
501 	 * @param curve the curve to split
502 	 * @return a set of non-self-intersecting continuous curves
503 	 */
504 	public static Collection<CirculinearContinuousCurve2D> 
505 	splitContinuousCurve(CirculinearContinuousCurve2D curve) {
506 		
507 		double pos0, pos1, pos2;
508 		
509 		// create the array of resulting curves
510         ArrayList<CirculinearContinuousCurve2D> result =
511         	new ArrayList<CirculinearContinuousCurve2D>();
512 
513         // Instances of CirculinearElement2D can not self-intersect
514 		if (curve instanceof CirculinearElement2D){
515 			result.add(curve);
516 			return result;
517 		}
518 		
519 		// convert the curve to a poly-circulinear curve, to be able to call
520 		// the "locateSelfIntersections" method.
521 		PolyCirculinearCurve2D<CirculinearElement2D> polyCurve = 
522 			createPolyCurve(curve.getSmoothPieces(), curve.isClosed());
523 		
524         // identify couples of intersections
525 		double[][] couples = locateSelfIntersections(polyCurve);
526 		
527 		// case of curve without self-intersections
528 		if(couples.length==0){			
529 	        // create continuous curve formed only by circulinear elements
530 			result.add(createPolyCurve(polyCurve.getSmoothPieces(),
531 					curve.isClosed()));
532 	        return result;
533 		}
534 		
535 		// put all positions into a tree map
536 		TreeMap<Double, Double> twins = new TreeMap<Double, Double>();
537         for (int i=0; i<couples.length; i++) {
538         	pos1 = couples[i][0];
539         	pos2 = couples[i][1];
540         	twins.put(pos1, pos2);
541         	twins.put(pos2, pos1);
542         }
543         
544         // an array for the portions of curves
545         ArrayList<CirculinearElement2D> elements;
546         
547         
548         // Process the first curve
549         
550         // create new empty array of elements for current continuous curve
551         elements = new ArrayList<CirculinearElement2D>();
552         
553         // get first intersection
554         pos1 = polyCurve.getT0();
555         pos2 = twins.firstKey();
556         pos0 = pos2;
557         
558         // add the first portion of curve, starting from the beginning
559         //elements.addAll(polyCurve.getSubCurve(pos1, pos2).getSmoothPieces());
560         addElements(elements, polyCurve.getSubCurve(pos1, pos2));
561         do {
562         	// get the position of the new portion of curve
563         	pos1 = twins.remove(pos2);
564         	
565         	// check if there are still intersections to process
566         	if(twins.higherKey(pos1)==null)
567         		break;
568         	
569         	// get position of next intersection on the curve
570         	pos2 = twins.higherKey(pos1);
571         	
572         	// add elements
573         	addElements(elements, polyCurve.getSubCurve(pos1, pos2));
574         } while(true);
575         
576         // add the last portion of curve, going to the end of original curve
577         pos2 = polyCurve.getT1();
578         addElements(elements, polyCurve.getSubCurve(pos1, pos2));
579         
580         // add the continuous curve formed only by circulinear elements
581         result.add(createPolyCurve(elements, curve.isClosed()));
582         
583         // Process other curves, while there are intersections left
584         while(!twins.isEmpty()) {
585             // create new empty array of elements for current continuous curve
586             elements = new ArrayList<CirculinearElement2D>();
587             
588             // get first intersection
589             pos0 = twins.firstKey();
590             pos1 = twins.get(pos0);
591             pos2 = twins.higherKey(pos1);
592             
593             // add the first portion of curve, starting from the beginning
594             addElements(elements, polyCurve.getSubCurve(pos1, pos2));
595             
596             while(pos2!=pos0) {
597             	// get the position of the new portion of curve
598             	pos1 = twins.remove(pos2);
599             	
600             	// check if there are still intersections to process
601             	if(twins.higherKey(pos1)==null)
602             		break;
603             	
604             	// get position of next intersection on the curve
605             	pos2 = twins.higherKey(pos1);
606             	
607             	// add elements
608             	addElements(elements, polyCurve.getSubCurve(pos1, pos2));
609             }
610             
611             pos1 = twins.remove(pos2);
612         	
613             // create continuous curve formed only by circulinear elements
614             // and add it to the set of curves
615             result.add(createPolyCurve(elements, true));
616         }
617         
618         return result;
619 	}
620 	
621 	/**
622 	 * This is a helper method, used to avoid excessive use of generics within
623 	 * other methods of the class.
624 	 */
625 	private static PolyCirculinearCurve2D<CirculinearElement2D>
626 	createPolyCurve(Collection<? extends CirculinearElement2D> elements, 
627 			boolean closed) {
628 		return new PolyCirculinearCurve2D<CirculinearElement2D>(
629 				elements, closed);
630 	}
631 	
632 	public static Collection<CirculinearContour2D> 
633 	splitIntersectingContours(
634 			CirculinearContour2D curve1, 
635 			CirculinearContour2D curve2) {
636 		
637 		double pos0, pos1, pos2;
638 		
639 		// ----------------
640 		// Initializations
641 		
642 		// create the array of resulting curves
643         ArrayList<CirculinearContour2D> contours =
644         	new ArrayList<CirculinearContour2D>();
645 
646 		// identify couples of intersections
647 		double[][] couples = locateIntersections(curve1, curve2);
648 		
649 		// case no intersection between the curves
650 		if(couples.length==0){			
651 	        // create continuous curve formed only by circulinear elements
652 			contours.add(curve1);
653 			contours.add(curve2);
654 	        return contours;
655 		}
656 		
657 		// stores couple of points in 'twins'
658 		TreeMap<Double, Double> twins1 = new TreeMap<Double, Double>();
659 		TreeMap<Double, Double> twins2 = new TreeMap<Double, Double>();
660 		
661 		// stores also positions on each curve in an ordered tree
662 		TreeSet<Double> positions1 = new TreeSet<Double>();
663 		TreeSet<Double> positions2 = new TreeSet<Double>();
664 		
665 		// iterate on intersections to populate the data
666         for (int i=0; i<couples.length; i++) {
667         	pos1 = couples[i][0];
668         	pos2 = couples[i][1];
669         	twins1.put(pos1, pos2);
670         	twins2.put(pos2, pos1);
671         	positions1.add(pos1);
672         	positions2.add(pos2);
673         }
674         
675         // an array for the portions of curves
676         ArrayList<CirculinearElement2D> elements;
677                 
678         // Process other curves, while there are intersections left
679         while(!twins1.isEmpty()) {
680             // create new empty array of elements for current contour
681             elements = new ArrayList<CirculinearElement2D>();
682             
683             // get first intersection
684             pos0 = twins2.firstEntry().getValue();
685             pos1 = pos0;
686             
687             do {
688                 pos2 = nextValue(positions1, pos1);
689                 
690                 // add a portion of the first curve
691                 addElements(elements, (CirculinearContinuousCurve2D)curve1.getSubCurve(pos1, pos2));
692                 
693                 // get the position of end intersection on second curve
694             	pos1 = twins1.remove(pos2);
695             	
696             	// get position of next intersection on the second curve
697             	pos2 = nextValue(positions2, pos1);
698             	
699             	// add a portion of the second curve
700             	addElements(elements, (CirculinearContinuousCurve2D)curve2.getSubCurve(pos1, pos2));
701                 
702                 // get the position of end intersection on first curve
703             	pos1 = twins2.remove(pos2);
704             	
705             } while (pos1!=pos0);
706             
707             // create continuous curve formed only by circulinear elements
708             // and add it to the set of curves
709             contours.add(
710             		new BoundaryPolyCirculinearCurve2D<CirculinearElement2D>(
711             		elements, true));
712         }
713         
714         return contours;
715 	}
716 	
717 	/**
718 	 * Split a collection of contours which possibly intersect each other to a
719 	 * set of contours which do not intersect each others. Each contour is
720 	 * assumed not to self-intersect.
721 	 */
722 	public static Collection<CirculinearContour2D>
723 	splitIntersectingContours(Collection<? extends CirculinearContour2D> curves) {
724 		
725 		double pos0=0, pos1, pos2;
726 		
727 		// ----------------
728 		// Initializations
729 		
730         // convert collection to array
731         CirculinearContour2D[] curveArray = 
732         	curves.toArray(new CirculinearContour2D[0]);
733         
734 		// Create array of tree maps for storing
735         // 1) index of crossing curve for each intersection of i-th curve
736         // 2) position on crossing curve of the intersection point
737         int nCurves = curves.size();
738         ArrayList<TreeMap<Double, Integer>>  twinIndices = 
739         	new ArrayList<TreeMap<Double, Integer>>(nCurves);
740         ArrayList<TreeMap<Double, Double>>  twinPositions = 
741         	new ArrayList<TreeMap<Double, Double>>(nCurves);
742         
743         // Populate the two arrays with empty trees
744         for(int i=0; i<nCurves; i++){
745         	twinIndices.add(i, new TreeMap<Double, Integer>());
746         	twinPositions.add(i, new TreeMap<Double, Double>());
747         }
748         
749         // Create array of tree sets for storing positions of intersections
750         // on each curve
751         ArrayList<TreeSet<Double>>  positions = 
752         	new ArrayList<TreeSet<Double>>(nCurves);
753         
754         // populate the array with empty tree sets
755         for(int i=0; i<nCurves; i++){
756         	positions.add(i, new TreeSet<Double>());
757         }
758        
759 		// identify couples of intersections on each couple (i,j) of curves
760 		for(int i=0; i<nCurves-1; i++) {
761 			CirculinearContour2D curve1 = curveArray[i];
762 			
763 			for(int j=i+1; j<nCurves; j++) {
764 				CirculinearContour2D curve2 = curveArray[j];
765 				double[][] couples = locateIntersections(curve1, curve2);
766 				
767 				// iterate on intersections to populate the data
768 		        for (int k=0; k<couples.length; k++) {
769 		        	// position on each curve
770 		        	pos1 = couples[k][0];
771 		        	pos2 = couples[k][1];
772 		        	
773 		        	// add positions in their tree sets
774 		        	positions.get(i).add(pos1);
775 		        	positions.get(j).add(pos2);
776 		        	
777 		        	// store indices of corresponding intersecting curves
778 		        	twinIndices.get(i).put(pos1, j);
779 		        	twinIndices.get(j).put(pos2, i);
780 		        	
781 		        	// store positions of intersection point on the 
782 		        	// corresponding curve
783 		        	twinPositions.get(i).put(pos1, pos2);
784 		        	twinPositions.get(j).put(pos2, pos1);
785 		        }
786 			}
787 		}		
788 		
789 		// create the array of resulting curves
790         ArrayList<CirculinearContour2D> contours =
791         	new ArrayList<CirculinearContour2D>();
792 		
793 		// process curves without intersections
794         for(int i=0; i<nCurves; i++) {
795         	// If the curve has no intersection, use it as contour
796         	if (twinPositions.get(i).isEmpty()) {
797         		contours.add(curveArray[i]);
798         	}
799         }
800        
801 		// process infinite curves
802         for(int i=0; i<nCurves; i++) {
803         	// filter bounded curves
804         	if (curveArray[i].isBounded())
805         		continue;
806         	
807         	// If the curve has no intersection, it was already processed
808         	if (twinPositions.get(i).isEmpty()) {
809         		continue;
810         	}
811         	
812         	// find first unprocessed intersection
813         	pos0 = twinPositions.get(i).firstEntry().getKey();
814         	int ind0 = twinIndices.get(i).firstEntry().getValue();
815         	
816             // create new empty array of elements for current contour
817         	ArrayList<CirculinearElement2D> elements =
818         		new ArrayList<CirculinearElement2D>();
819 
820         	// add portion of curve until intersection
821         	CirculinearContour2D curve0 = curveArray[i];
822         	addElements(elements, (CirculinearContinuousCurve2D)curve0.getSubCurve(curve0.getT0(), pos0));
823         	
824         	// init
825             pos1 = twinPositions.get(i).firstEntry().getValue();
826             int ind  = ind0;
827             
828             do {
829             	// the current contour
830             	CirculinearContour2D curve = curveArray[ind];
831             	
832             	// extract next position
833                 pos2 = nextValue(positions.get(ind), pos1);
834                 
835                 if((pos2<pos1) && !curve.isBounded()) {
836                 	// We got the last point of an infinite curve.
837                 	// That means we just finished the current free contour
838                 	// and we just need to add elements
839                 	addElements(elements, (CirculinearContinuousCurve2D)curve.getSubCurve(pos1, curve.getT1()));              	
840                 } else {
841                 	// simple case:
842                 	// add a portion of the current curve to the element list
843                 	addElements(elements, (CirculinearContinuousCurve2D)curve.getSubCurve(pos1, pos2));
844                     
845                     // get the position of end intersection on second curve
846                     pos1 = twinPositions.get(ind).remove(pos2);
847                     ind  = twinIndices.get(ind).remove(pos2);            	
848                 }
849             } while (ind!=ind0);
850             
851             twinPositions.get(i).remove(pos0);
852         	twinIndices.get(i).remove(pos0);
853         	
854             // create continuous curve formed only by circulinear elements
855             // and add it to the set of curves
856             contours.add(
857             		BoundaryPolyCirculinearCurve2D.create(elements, true));
858         }
859         
860                
861         // Process other curves, while there are intersections left
862         while(!isAllEmpty(twinPositions)) {
863             // create new empty array of elements for current contour
864         	ArrayList<CirculinearElement2D> elements =
865         		new ArrayList<CirculinearElement2D>();
866             
867             // indices of the two considered curves.
868             int ind0=0, ind;
869             
870             // get first intersection
871             for(int i=0;i<nCurves;i++) {
872             	// find a curve with unprocessed intersections
873             	if(twinPositions.get(i).isEmpty())
874             		continue;
875             	
876             	// find first unprocessed intersection
877             	pos0 = twinPositions.get(i).firstEntry().getValue();
878             	ind0 = twinIndices.get(i).firstEntry().getValue();
879             	break;
880             }
881             
882             if (ind0==0) {
883             	System.out.println("No more intersections, but was not detected");
884             }
885             
886             pos1 = pos0;
887             ind  = ind0;
888             
889             do {
890                 pos2 = nextValue(positions.get(ind), pos1);
891                 
892                 // add a portion of the first curve
893                 addElements(elements, (CirculinearContinuousCurve2D)curveArray[ind].getSubCurve(pos1, pos2));
894                 
895                 // get the position of end intersection on second curve
896                 pos1 = twinPositions.get(ind).remove(pos2);
897                 ind  = twinIndices.get(ind).remove(pos2);            	
898             } while (pos1!=pos0 || ind!=ind0);
899             
900             // create continuous curve formed only by circulinear elements
901             // and add it to the set of curves
902             contours.add(
903             		BoundaryPolyCirculinearCurve2D.create(elements, true));
904         }
905         
906         return contours;
907 	}
908 	
909 	/**
910 	 * Add all circulinear elements of the given curve to the collection of
911 	 * circulinear elements.
912 	 */
913 	private static void addElements(
914 			Collection<CirculinearElement2D> elements,
915 			CirculinearContinuousCurve2D curve) {
916 		elements.addAll(curve.getSmoothPieces());
917 	}
918 	
919 	private static boolean isAllEmpty(Collection<TreeMap<Double, Double>> coll) {
920 		for(TreeMap<?,?> map : coll) {
921 			if (!map.isEmpty())
922 				return false;
923 		}
924 		return true;
925 	}
926 	
927 	/**
928 	 * Returns either the next value, or the first value of the tree if the
929 	 * given value is the last one of the tree.
930 	 */
931 	private static double nextValue(TreeSet<Double> tree, double value) {
932 		if(tree.higher(value)==null)
933 			return tree.first();
934 		else
935 			return tree.higher(value);
936 	}
937 	
938 	/**
939 	 * Compute the buffer of a circulinear curve.<p>
940 	 * The algorithm is as folow:
941 	 * <ol>
942 	 * <li> split the curve into a set of curves without self-intersections
943 	 * <li> for each splitted curve, compute the contour of its buffer
944 	 * <li> split self-intersecting contours into set of disjoint contours
945 	 * <li> split all contour which intersect each other to disjoint contours
946 	 * <li> remove contours which are too close from the original curve
947 	 * <li> create a new domain with the final set of contours
948 	 * </ol>
949 	 */
950 	public static CirculinearDomain2D computeBuffer(
951 			CirculinearCurve2D curve, double dist) {
952 		
953 		ArrayList<CirculinearContour2D> contours =
954 			new ArrayList<CirculinearContour2D>();
955 		
956 		// iterate on all continuous curves
957 		for(CirculinearContinuousCurve2D cont : curve.getContinuousCurves()) {
958 			// split the curve into a set of non self-intersecting curves
959 			for(CirculinearContinuousCurve2D splitted : 
960 				splitContinuousCurve(cont)) {
961 				// compute the rings composing the simple curve buffer
962 				contours.addAll(computeBufferSimpleContour(splitted, dist));
963 			}
964 		}
965 		
966 		// split contours which intersect each others
967 		contours = new ArrayList<CirculinearContour2D>(
968 				splitIntersectingContours(contours));		
969 		
970 		// Remove contours that cross or that are too close from base curve
971 		ArrayList<CirculinearContour2D> contours2 = 
972 			new ArrayList<CirculinearContour2D>(contours.size());
973 		for(CirculinearContour2D contour : contours) {
974 			
975 			// do not keep contours which cross original curve
976 			if(findIntersections(curve, contour).size()>0)
977 				continue;
978 			
979 			// check that vertices of contour are not too close from original
980 			// curve
981 			double distCurves = 
982 				getDistanceCurveSingularPoints(curve, contour);
983 			if(distCurves<dist-Shape2D.ACCURACY)
984 				continue;
985 			
986 			// keep the contours that meet the above conditions
987 			contours2.add(contour);
988 		}
989 		
990 		// All the rings are created, we can now create a new domain with the
991 		// set of rings
992 		return new GenericCirculinearDomain2D(
993 				new CirculinearBoundarySet2D<CirculinearContour2D>(
994 						contours2));
995 	}
996 	
997 	/**
998 	 * Compute buffer of a point set.
999 	 */
1000 	public static CirculinearDomain2D computeBuffer(PointSet2D set, 
1001 			double dist) {
1002 		// create array for storing result
1003 		Collection<CirculinearContour2D> contours = 
1004 			new ArrayList<CirculinearContour2D>(set.getPointNumber());
1005 		
1006 		// for each point, add a new circle
1007 		for(Point2D point : set) {
1008 			contours.add(new Circle2D(point, Math.abs(dist), dist>0));
1009 		}
1010 		
1011 		// process circles to remove intersections
1012 		contours = splitIntersectingContours(contours);
1013 		
1014 		// Remove contours that cross or that are too close from base curve
1015 		ArrayList<CirculinearContour2D> contours2 = 
1016 			new ArrayList<CirculinearContour2D>(contours.size());
1017 		for(CirculinearContour2D ring : contours) {
1018 			
1019 			// check that vertices of contour are not too close from original
1020 			// curve
1021 			double minDist = getDistanceCurvePoints(ring, set.getPoints());
1022 			if(minDist<dist-Shape2D.ACCURACY)
1023 				continue;
1024 			
1025 			// keep the contours that meet the above conditions
1026 			contours2.add(ring);
1027 		}
1028 
1029 		return new GenericCirculinearDomain2D(new CirculinearBoundarySet2D(contours2));
1030 	}
1031 
1032 	/**
1033 	 * Computes the rings that form the buffer of a continuous circulinear
1034 	 * curve that does not self-intersect.
1035 	 */
1036 	public static Collection<? extends CirculinearContour2D> 
1037 	computeBufferSimpleContour(CirculinearContinuousCurve2D curve, double d) {
1038 		
1039 		Collection<CirculinearContinuousCurve2D> parallels = 
1040 			createFreeParallels(curve, d);
1041 		
1042 		Collection<CirculinearContour2D> contours = 
1043 			createContoursFromParallels(curve, parallels);
1044 		
1045 		// some contours may intersect, so we split them
1046 		Collection<CirculinearContour2D> contours2 =
1047 			removeIntersectingContours(contours, curve, d);
1048 
1049 		// return the set of created contours
1050 		return contours2;
1051 	}
1052 	
1053 	/**
1054 	 * Compute the 2 parallels of a given circulinear curve, process
1055 	 * self-intersections, and remove parallel pieces that cross the original
1056 	 * curve.
1057 	 */
1058 	private static Collection<CirculinearContinuousCurve2D> createFreeParallels(
1059 			CirculinearContinuousCurve2D curve, double d) {
1060 		
1061 		// the parallel in each side
1062 		CirculinearContinuousCurve2D parallel1, parallel2;
1063 		parallel1 = (CirculinearContinuousCurve2D)curve.getParallel(d);
1064 		parallel2 = (CirculinearContinuousCurve2D)curve.getParallel(-d).getReverseCurve();
1065 		
1066 		// split each parallel into continuous curves
1067 		ArrayList<CirculinearContinuousCurve2D> curves =
1068 			new ArrayList<CirculinearContinuousCurve2D>();
1069 		
1070 		// select only curve parts which do not cross original curve
1071 		for(CirculinearContinuousCurve2D split : splitContinuousCurve(parallel1)) {
1072 			if(findIntersections(curve, split).size()==0)
1073 				curves.add(split);
1074 		}
1075 		for(CirculinearContinuousCurve2D split : splitContinuousCurve(parallel2)) {
1076 			if(findIntersections(curve, split).size()==0)
1077 				curves.add(split);
1078 		}
1079 		
1080 		return curves;
1081 	}
1082 
1083 	/**
1084 	 * Generate a set of contour from a set of parallels. If the curve is
1085 	 * closed, return 2 contours. Otherwise, return only one contours, that
1086 	 * can possibly self-intersect.
1087 	 */
1088 	private static Collection<CirculinearContour2D> createContoursFromParallels(
1089 			CirculinearContinuousCurve2D curve, 
1090 			Collection<CirculinearContinuousCurve2D> parallels) {
1091 		// create array for storing result
1092 		ArrayList<CirculinearContour2D> contours = 
1093 			new ArrayList<CirculinearContour2D>();
1094 		
1095 		// If the original curve is closed, create a new contour from each
1096 		// parallel curve
1097 		if(curve.isClosed()){
1098 			for(CirculinearContinuousCurve2D continuous : parallels) {
1099 				contours.add(convertCurveToBoundary(continuous));
1100 			}
1101 			return contours;
1102 		} 
1103 		
1104 		return createContoursFromParallels(parallels);
1105 	}
1106 	
1107 	/**
1108 	 * Creates the unique contour based on two parallels of the base curve, by
1109 	 * adding appropriate circle arcs at extremities of the base curve.
1110 	 */
1111 	private static Collection<CirculinearContour2D> 
1112 	createContoursFromParallels(
1113 			Collection<CirculinearContinuousCurve2D> parallels) {
1114 		
1115 		// create array for storing result
1116 		ArrayList<CirculinearContour2D> contours = 
1117 			new ArrayList<CirculinearContour2D>();
1118 		
1119 		// There should be only 2 curves in the list 'curves' that are
1120 		// not rings
1121 		CirculinearContinuousCurve2D curve1=null;
1122 		CirculinearContinuousCurve2D curve2=null;
1123 
1124 		for(CirculinearContinuousCurve2D continuous : parallels) {
1125 			if(continuous.isClosed()){
1126 				// simply adds a new ring by using same elements
1127 				contours.add(convertCurveToBoundary(continuous));
1128 			} else {
1129 				if(curve1==null){
1130 					curve1 = continuous;
1131 				} else if (curve2==null) {
1132 					curve2 = continuous;
1133 				} else {
1134 					//TODO: throw exception instead of this ugly error management
1135 					System.err.println("more than 2 free curves....");
1136 					return contours;
1137 				}
1138 			}
1139 		}
1140 
1141 		if(curve1!=null && curve2!=null) {
1142 			contours.addAll(createSingleContourFromTwoParallels(curve1, curve2));
1143 		}
1144 		
1145 		return contours;
1146 	}
1147 	
1148 	/**
1149 	 * Creates the unique contour based on two parallels of the base curve, by
1150 	 * adding appropriate circle arcs at extremities of the base curve.
1151 	 */
1152 	private static Collection<CirculinearContour2D> 
1153 	createSingleContourFromTwoParallels(
1154 			CirculinearContinuousCurve2D curve1,
1155 			CirculinearContinuousCurve2D curve2) {
1156 		
1157 		// create array for storing result
1158 		ArrayList<CirculinearContour2D> contours = 
1159 			new ArrayList<CirculinearContour2D>();
1160 		
1161 		// create new ring using two open curves and two circle arcs
1162 		if(curve1!=null && curve2!=null){
1163 			// array of elements for creating new ring.
1164 			ArrayList<CirculinearElement2D> elements = 
1165 				new ArrayList<CirculinearElement2D>();
1166 
1167 			// some shortcuts for computing infinity of curve
1168 			boolean b0 = Curve2DUtils.isLeftInfinite(curve1);
1169 			boolean b1 = Curve2DUtils.isRightInfinite(curve1);
1170 
1171 			if (b0 && b1) {
1172 				// case of an infinite curve at both extremities
1173 				// In this case, the two parallel curves do not join,
1174 				// and are added as contours individually					
1175 				contours.add(convertCurveToBoundary(curve1));
1176 				contours.add(convertCurveToBoundary(curve2));
1177 			} else if (b0 && !b1) {
1178 				// case of a curve starting from infinity, and finishing
1179 				// on a given point
1180 
1181 				// extremity points
1182 				Point2D p11 = curve1.getFirstPoint();
1183 				Point2D p22 = curve2.getLastPoint();
1184 
1185 				// add elements of the new contour
1186 				elements.addAll(curve2.getSmoothPieces());
1187 				elements.add(createCircularCap(p22, p11));
1188 				elements.addAll(curve1.getSmoothPieces());
1189 
1190 				// create the last ring
1191 				contours.add(new GenericCirculinearRing2D(elements));
1192 			} else if (b1 && !b0) {
1193 				// case of a curve starting at a point and finishing at
1194 				// the infinity
1195 
1196 				// extremity points
1197 				Point2D p12 = curve1.getLastPoint();
1198 				Point2D p21 = curve2.getFirstPoint();
1199 
1200 				// add elements of the new contour
1201 				elements.addAll(curve1.getSmoothPieces());
1202 				elements.add(createCircularCap(p12, p21));
1203 				elements.addAll(curve2.getSmoothPieces());
1204 
1205 				// create the last contour
1206 				contours.add(new GenericCirculinearRing2D(elements));
1207 
1208 			} else {
1209 				// case of a curve finite at each extremity
1210 
1211 				// extremity points
1212 				Point2D p11 = curve1.getFirstPoint();
1213 				Point2D p12 = curve1.getLastPoint();
1214 				Point2D p21 = curve2.getFirstPoint();
1215 				Point2D p22 = curve2.getLastPoint();
1216 
1217 				// Check how to associate open curves and circle arcs
1218 				//TODO: maybe replace by a dedicated method that could manage several types of junctions ?
1219 				elements.addAll(curve1.getSmoothPieces());					
1220 				elements.add(createCircularCap(p12, p21));
1221 				elements.addAll(curve2.getSmoothPieces());
1222 				elements.add(createCircularCap(p22, p11));
1223 				
1224 				// create the last ring
1225 				contours.add(new GenericCirculinearRing2D(elements));
1226 			}
1227 		}
1228 		
1229 		return contours;
1230 	}
1231 	
1232 	private static Collection<CirculinearContour2D> removeIntersectingContours (
1233 			Collection<CirculinearContour2D> contours, 
1234 			CirculinearCurve2D curve, double d) {
1235 		// prepare an array to store the set of rings
1236 		ArrayList<CirculinearContour2D> contours2 =
1237 			new ArrayList<CirculinearContour2D>();
1238 
1239 		// iterate on the set of rings
1240 		for(CirculinearContour2D contour : contours)
1241 			// split rings into curves which do not self-intersect
1242 			for(CirculinearContinuousCurve2D splitted : 
1243 				splitContinuousCurve(contour)) {
1244 				
1245 				// compute distance to original curve
1246 				// (assuming it is sufficient to compute distance to vertices
1247 				// of the reference curve).
1248 				double dist = getDistanceCurvePoints(curve, 
1249 						splitted.getSingularPoints());
1250 				
1251 				// check if distance condition is verified
1252 				if(dist-d<-Shape2D.ACCURACY)
1253 					continue;
1254 				
1255 				// convert the set of elements to a Circulinear ring
1256 				contours2.add(convertCurveToBoundary(splitted));
1257 		}
1258 		
1259 		// return the set of created rings
1260 		return contours2;		
1261 	}
1262 	
1263 	/**
1264 	 * Converts the given continuous curve to an instance of
1265 	 * CirculinearContour2D. This can be the curve itself, a new instance of
1266 	 * GenericCirculinearRing2D if the curve is bounded, or a new instance of
1267 	 * BoundaryPolyCirculinearCurve2D if the curve is unbounded.
1268 	 */
1269 	private static CirculinearContour2D convertCurveToBoundary (
1270 			CirculinearContinuousCurve2D curve) {
1271 		// basic case: curve is already a contour
1272 		if (curve instanceof CirculinearContour2D)
1273 			return (CirculinearContour2D) curve;
1274 		
1275 		// if the curve is closed, return an instance of GenericCirculinearRing2D
1276 		if (curve.isClosed())
1277 			return GenericCirculinearRing2D.create(curve.getSmoothPieces());
1278 		
1279 		return BoundaryPolyCirculinearCurve2D.create(curve.getSmoothPieces());
1280 	}
1281 		
1282 	private static CircleArc2D createCircularCap(Point2D p1, Point2D p2){
1283 		Point2D center = Point2D.midPoint(p1, p2);
1284 		double radius = p1.getDistance(p2)/2;
1285 		double angle1 = Angle2D.getHorizontalAngle(center, p1);
1286 		double angle2 = Angle2D.getHorizontalAngle(center, p2);
1287 		return CircleArc2D.create(center, radius, angle1, angle2, true);
1288 	}
1289 	
1290 	public static double getDistanceCurvePoints(
1291 			CirculinearCurve2D curve, Collection<? extends Point2D> points){
1292 		double minDist = Double.MAX_VALUE;
1293 		for(Point2D point : points){
1294 			minDist = Math.min(minDist, curve.getDistance(point));
1295 		}
1296 		return minDist;
1297 	}
1298 	
1299 	private static double getDistanceCurveSingularPoints(
1300 			CirculinearCurve2D ref, CirculinearCurve2D curve){
1301 		// extract singular points
1302 		Collection<Point2D> points = curve.getSingularPoints();
1303 		
1304 		// If no singular point, choose an arbitrary point on the curve
1305 		if(points.isEmpty()) {
1306 			points = new ArrayList<Point2D>();
1307 			double t = Curve2DUtils.choosePosition(curve.getT0(), curve.getT1());
1308 			points.add(curve.getPoint(t));
1309 		}
1310 		
1311 		// Iterate on points to get minimal distance
1312 		double minDist = Double.MAX_VALUE;
1313 		for(Point2D point : points){
1314 			minDist = Math.min(minDist, ref.getDistance(point));
1315 		}
1316 		return minDist;
1317 	}
1318 }