View Javadoc
1   package org.opentrafficsim.core.geometry;
2   
3   import java.io.Serializable;
4   import java.util.Locale;
5   import java.util.concurrent.Callable;
6   import java.util.concurrent.ExecutionException;
7   import java.util.concurrent.ExecutorService;
8   import java.util.concurrent.Executors;
9   import java.util.concurrent.FutureTask;
10  import java.util.concurrent.TimeUnit;
11  import java.util.concurrent.TimeoutException;
12  
13  import org.opentrafficsim.core.network.NetworkException;
14  
15  import nl.tudelft.simulation.language.d3.DirectedPoint;
16  
17  /**
18   * <p>
19   * Copyright (c) 2013-2019 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
20   * BSD-style license. See <a href="http://opentrafficsim.org/docs/license.html">OpenTrafficSim License</a>.
21   * </p>
22   * $LastChangedDate: 2015-07-24 02:58:59 +0200 (Fri, 24 Jul 2015) $, @version $Revision: 1147 $, by $Author: averbraeck $,
23   * initial version Nov 9, 2015 <br>
24   * @author <a href="http://www.tbm.tudelft.nl/averbraeck">Alexander Verbraeck</a>
25   * @author <a href="http://www.tudelft.nl/pknoppers">Peter Knoppers</a>
26   */
27  public final class Test
28  {
29      /** */
30      private Test()
31      {
32      }
33  
34      /**
35       * Apply all offset methods and check the results.
36       * @param reference OTSLine3D; reference line
37       * @param offset double; the offset
38       * @return int; the number of failures
39       */
40      public static String checkAll(final OTSLine3D reference, final double offset)
41      {
42          String result = "";
43          for (OTSLine3D.OffsetMethod offsetMethod : new OTSLine3D.OffsetMethod[] { OTSLine3D.OffsetMethod.JTS,
44                  OTSLine3D.OffsetMethod.PK })
45          {
46              result += timeLimitedCheckOffsetLine(reference, offset, offsetMethod, 5000);
47              result += timeLimitedCheckOffsetLine(reference, -offset, offsetMethod, 5000);
48              /*-
49              if (!checkOffsetLine(reference, offset, offsetMethod))
50              {
51                  result += "fail " + offsetMethod + " " + offset + " ";
52              }
53              if (!checkOffsetLine(reference, -offset, offsetMethod))
54              {
55                  result += "fail " + offsetMethod + " " + (-offset) + " ";
56              }
57               */
58          }
59          return result;
60      }
61  
62      /**
63       * @param reference OTSLine3D; the reference line
64       * @param offset double; the offset
65       * @param offsetMethod OTSLine3D.OffsetMethod; the offset method
66       * @param timeLimitMillis int; maximum running time in milliseconds
67       * @return String; empty string on success, description of the result on failure
68       */
69      public static String timeLimitedCheckOffsetLine(final OTSLine3D reference, final double offset,
70              final OTSLine3D.OffsetMethod offsetMethod, final int timeLimitMillis)
71      {
72          Callable<String> callable = new Test().new MyCallable(reference, offset, offsetMethod);
73          FutureTask<String> futureTask = new FutureTask<String>(callable);
74          ExecutorService executor = Executors.newFixedThreadPool(1);
75          executor.execute(futureTask);
76          String result = "";
77  
78          try
79          {
80              result = futureTask.get(timeLimitMillis, TimeUnit.MILLISECONDS);
81          }
82          catch (InterruptedException | ExecutionException | TimeoutException exception)
83          {
84              result = "time out ";
85          }
86          // There is something very non-trivial about shutting down an ExecutorService
87          // This code adapted from http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html
88          executor.shutdown(); // Disable new tasks from being submitted
89          try
90          {
91              // Wait a while for existing tasks to terminate
92              if (!executor.awaitTermination(60, TimeUnit.MILLISECONDS))
93              {
94                  executor.shutdownNow(); // Cancel currently executing tasks
95                  // Wait a while for tasks to respond to being cancelled
96                  if (!executor.awaitTermination(60, TimeUnit.MILLISECONDS))
97                  {
98                      System.err.println("executor did not terminate");
99                  }
100             }
101         }
102         catch (InterruptedException ie)
103         {
104             // (Re-)Cancel if current thread also interrupted
105             executor.shutdownNow();
106             // Preserve interrupt status
107             Thread.currentThread().interrupt();
108         }
109         return String.format(Locale.US, "%3.3s %6.1f: %-8.8s  ", offsetMethod, offset, result);
110     }
111 
112     /**
113      * @param args String[]; args
114      * @throws NetworkException on error
115      * @throws OTSGeometryException on error
116      */
117     public static void main(final String[] args) throws NetworkException, OTSGeometryException
118     {
119         OTSLine3D reference;
120         // OTSLine3D.debugOffsetLine = true;
121 
122         reference = new OTSLine3D(new OTSPoint3D(5, 2.5), new OTSPoint3D(4.8, 2.5), new OTSPoint3D(4.6, 2.7),
123                 new OTSPoint3D(2.2, 2.7), new OTSPoint3D(2.2, 5));
124         System.out.println("Kink near start:                                    " + checkAll(reference, 2));
125 
126         reference = new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(10, 5, 0), new OTSPoint3D(20, 0, 0));
127         System.out.println("Single direction change far from ends:              " + checkAll(reference, 2));
128 
129         reference = new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(20, 10, 0), new OTSPoint3D(21, 10, 0),
130                 new OTSPoint3D(22, 9.5, 0), new OTSPoint3D(30, 0, 0));
131         System.out.println("Double direction change far from ends:              " + checkAll(reference, -3));
132 
133         // Reference line closely spaced points on a (relatively large) circle
134         OTSPoint3D[] designLinePoints = new OTSPoint3D[8];
135         double radius = 10;
136         double angleStep = Math.PI / 1000;
137         double initialAngle = Math.PI / 4;
138         for (int i = 0; i < designLinePoints.length; i++)
139         {
140             double angle = initialAngle + i * angleStep;
141             designLinePoints[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle) - radius, 0);
142         }
143         reference = new OTSLine3D(designLinePoints);
144         // passes all
145         System.out.println("Closely spaced points on large circle:              " + checkAll(reference, 2));
146 
147         // Straight design line with some <i>noise</i> (sufficiently far from the end points).
148         reference = new OTSLine3D(new OTSPoint3D(10, 10, 0), new OTSPoint3D(9.999, 8, 0), new OTSPoint3D(9.996, 7.99, 0),
149                 new OTSPoint3D(9.999, 7.98, 0), new OTSPoint3D(10.03, 7.95, 0), new OTSPoint3D(10.01, 7.94, 0),
150                 new OTSPoint3D(10.0, 7.94, 0), new OTSPoint3D(10, 6, 0), new OTSPoint3D(10, 2, 0));
151         System.out.println("Straight reference with noise far from ends:        " + checkAll(reference, 2));
152 
153         // Straight design line with some <i>noise</i> (close to the end points).
154         reference = new OTSLine3D(new OTSPoint3D(5, -1, 0), new OTSPoint3D(5, -2, 0), new OTSPoint3D(4.9, -2.01, 0),
155                 new OTSPoint3D(5.1, -2.03, 0), new OTSPoint3D(5, -2.04, 0), new OTSPoint3D(5, -6, 0),
156                 new OTSPoint3D(4.9, -6.01, 0), new OTSPoint3D(5.1, -6.03, 0), new OTSPoint3D(5, -6.04, 0),
157                 new OTSPoint3D(5, -7.04, 0));
158         System.out.println("Straight reference with noise near ends:            " + checkAll(reference, 2));
159 
160         // OTSOffsetLinePK.debugOffsetLine = true;
161         // checkOffsetLine(reference, -2, OTSLine3D.OffsetMethod.PK);
162 
163         reference = new OTSLine3D(new OTSPoint3D(10, 10, 0), new OTSPoint3D(10, 8, 0), new OTSPoint3D(0, 6, 0),
164                 new OTSPoint3D(10, 4, 0), new OTSPoint3D(10, 0, 0));
165         System.out.println("AV line0:                                           " + checkAll(reference, 1.625));
166 
167         reference = new OTSLine3D(new OTSPoint3D(10, 10, 0), new OTSPoint3D(9.999, 8, 0), new OTSPoint3D(9.996, 7.99, 0),
168                 new OTSPoint3D(9.999, 7.98, 0), new OTSPoint3D(10.03, 7.95, 0), new OTSPoint3D(10.01, 7.94, 0),
169                 new OTSPoint3D(10.0, 7.94, 0), new OTSPoint3D(10, 6, 0), new OTSPoint3D(10, 2, 0));
170         System.out.println("AV line1:                                           " + checkAll(reference, 1.625));
171 
172         reference = new OTSLine3D(new OTSPoint3D(10, 10, 0), new OTSPoint3D(9.999, 8, 0), new OTSPoint3D(9.996, 7.99, 0),
173                 new OTSPoint3D(9.999, 7.98, 0), new OTSPoint3D(10.03, 7.95, 0), new OTSPoint3D(10.01, 7.94, 0),
174                 new OTSPoint3D(10.0, 7.94, 0), new OTSPoint3D(10, 6, 0), new OTSPoint3D(9.999, 6, 0),
175                 new OTSPoint3D(9.996, 5.99, 0), new OTSPoint3D(9.999, 5.98, 0), new OTSPoint3D(10.03, 5.95, 0),
176                 new OTSPoint3D(10.01, 5.94, 0), new OTSPoint3D(10.0, 5.94, 0), new OTSPoint3D(10, 2, 0));
177         System.out.println("AV line2:                                           " + checkAll(reference, 1.625));
178 
179         reference = new OTSLine3D(new OTSPoint3D(-115.3680561332295, -548.0151713307242, 0.0),
180                 new OTSPoint3D(-121.1405898342023, -546.9967679699366, 0.0),
181                 new OTSPoint3D(-133.3954402170488, -545.1596234831587, 0.0),
182                 new OTSPoint3D(-133.49497466097273, -545.1499853728319, 0.0),
183                 new OTSPoint3D(-133.59452107477017, -545.1404716880575, 0.0),
184                 new OTSPoint3D(-133.69407930289987, -545.1310824437005, 0.0),
185                 new OTSPoint3D(-133.7936491898021, -545.1218176544314, 0.0),
186                 new OTSPoint3D(-133.89323057989893, -545.1126773347269, 0.0),
187                 new OTSPoint3D(-133.99282331759446, -545.1036614988684, 0.0),
188                 new OTSPoint3D(-134.09242724727505, -545.0947701609432, 0.0),
189                 new OTSPoint3D(-134.19204221330963, -545.086003334844, 0.0),
190                 new OTSPoint3D(-134.29166806004977, -545.077361034269, 0.0),
191                 new OTSPoint3D(-134.39130463183014, -545.0688432727218, 0.0),
192                 new OTSPoint3D(-134.4909517729686, -545.0604500635113, 0.0),
193                 new OTSPoint3D(-134.59060932776654, -545.0521814197522, 0.0),
194                 new OTSPoint3D(-134.690277140509, -545.0440373543638, 0.0),
195                 new OTSPoint3D(-134.78995505546513, -545.0360178800717, 0.0),
196                 new OTSPoint3D(-134.88964291688814, -545.0281230094058, 0.0),
197                 new OTSPoint3D(-134.98934056901578, -545.0203527547022, 0.0),
198                 new OTSPoint3D(-135.08904785607044, -545.0127071281019, 0.0),
199                 new OTSPoint3D(-135.18876462225958, -545.005186141551, 0.0),
200                 new OTSPoint3D(-135.28849071177578, -544.9977898068012, 0.0),
201                 new OTSPoint3D(-135.38822596879697, -544.9905181354092, 0.0),
202                 new OTSPoint3D(-135.4879702374869, -544.9833711387371, 0.0),
203                 new OTSPoint3D(-135.58772336199513, -544.9763488279517, 0.0),
204                 new OTSPoint3D(-135.68748518645745, -544.9694512140259, 0.0),
205                 new OTSPoint3D(-135.78725555499602, -544.9626783077368, 0.0),
206                 new OTSPoint3D(-135.88703431171965, -544.9560301196673, 0.0),
207                 new OTSPoint3D(-135.98682130072405, -544.9495066602052, 0.0),
208                 new OTSPoint3D(-136.08661636609207, -544.9431079395432, 0.0),
209                 new OTSPoint3D(-136.18641935189396, -544.9368339676794, 0.0),
210                 new OTSPoint3D(-136.28623010218757, -544.9306847544171, 0.0),
211                 new OTSPoint3D(-136.38604846101862, -544.9246603093641, 0.0),
212                 new OTSPoint3D(-136.48587427242094, -544.9187606419338, 0.0),
213                 new OTSPoint3D(-136.58570738041672, -544.9129857613443, 0.0),
214                 new OTSPoint3D(-136.68554762901675, -544.907335676619, 0.0),
215                 new OTSPoint3D(-136.78539486222067, -544.9018103965861, 0.0),
216                 new OTSPoint3D(-136.88524892401722, -544.8964099298789, 0.0),
217                 new OTSPoint3D(-136.98510965838437, -544.8911342849353, 0.0),
218                 new OTSPoint3D(-137.08497690928982, -544.8859834699989, 0.0),
219                 new OTSPoint3D(-137.18485052069096, -544.8809574931176, 0.0),
220                 new OTSPoint3D(-137.28473033653535, -544.8760563621447, 0.0),
221                 new OTSPoint3D(-137.38461620076075, -544.8712800847381, 0.0),
222                 new OTSPoint3D(-137.48450795729553, -544.8666286683607, 0.0),
223                 new OTSPoint3D(-137.58440545005882, -544.8621021202804, 0.0),
224                 new OTSPoint3D(-137.68430852296086, -544.8577004475699, 0.0),
225                 new OTSPoint3D(-137.78421701990308, -544.8534236571068, 0.0),
226                 new OTSPoint3D(-137.8841307847785, -544.8492717555735, 0.0),
227                 new OTSPoint3D(-137.98404966147183, -544.8452447494575, 0.0),
228                 new OTSPoint3D(-138.08397349385993, -544.841342645051, 0.0),
229                 new OTSPoint3D(-138.18390212581176, -544.837565448451, 0.0),
230                 new OTSPoint3D(-138.28383540118887, -544.8339131655592, 0.0),
231                 new OTSPoint3D(-138.38377316384558, -544.8303858020826, 0.0),
232                 new OTSPoint3D(-138.4837152576291, -544.8269833635323, 0.0),
233                 new OTSPoint3D(-138.58366152637993, -544.8237058552252, 0.0),
234                 new OTSPoint3D(-138.68361181393206, -544.8205532822818, 0.0),
235                 new OTSPoint3D(-138.78356596411322, -544.8175256496284, 0.0),
236                 new OTSPoint3D(-138.883523820745, -544.8146229619954, 0.0),
237                 new OTSPoint3D(-138.98348522764337, -544.8118452239183, 0.0),
238                 new OTSPoint3D(-139.08345002861856, -544.8091924397376, 0.0),
239                 new OTSPoint3D(-139.18341806747563, -544.806664613598, 0.0),
240                 new OTSPoint3D(-139.28338918801452, -544.8042617494492, 0.0),
241                 new OTSPoint3D(-139.38336323403036, -544.8019838510459, 0.0),
242                 new OTSPoint3D(-139.48334004931382, -544.7998309219471, 0.0),
243                 new OTSPoint3D(-139.58331947765103, -544.7978029655169, 0.0),
244                 new OTSPoint3D(-139.6833013628242, -544.7958999849238, 0.0),
245                 new OTSPoint3D(-139.78328554861167, -544.7941219831416, 0.0),
246                 new OTSPoint3D(-139.88327187878815, -544.7924689629479, 0.0),
247                 new OTSPoint3D(-139.98326019712502, -544.7909409269257, 0.0),
248                 new OTSPoint3D(-140.08325034739056, -544.7895378774629, 0.0),
249                 new OTSPoint3D(-140.18324217335015, -544.7882598167514, 0.0),
250                 new OTSPoint3D(-140.28323551876667, -544.7871067467883, 0.0),
251                 new OTSPoint3D(-140.38323022740042, -544.7860786693752, 0.0),
252                 new OTSPoint3D(-140.48322614300977, -544.7851755861186, 0.0),
253                 new OTSPoint3D(-140.58322310935108, -544.7843974984295, 0.0),
254                 new OTSPoint3D(-140.68322097017915, -544.7837444075236, 0.0),
255                 new OTSPoint3D(-140.7832195692473, -544.7832163144215, 0.0),
256                 new OTSPoint3D(-140.88321875030778, -544.7828132199481, 0.0),
257                 new OTSPoint3D(-140.98321835711187, -544.7825351247336, 0.0),
258                 new OTSPoint3D(-141.0832182334102, -544.7823820292122, 0.0),
259                 new OTSPoint3D(-141.18321822295303, -544.7823539336232, 0.0),
260                 new OTSPoint3D(-141.28321816949028, -544.7824508380106, 0.0),
261                 new OTSPoint3D(-141.38321791677217, -544.7826727422229, 0.0),
262                 new OTSPoint3D(-141.48321730854906, -544.7830196459133, 0.0),
263                 new OTSPoint3D(-141.58321618857192, -544.7834915485399, 0.0),
264                 new OTSPoint3D(-141.68321440059256, -544.7840884493653, 0.0),
265                 new OTSPoint3D(-141.7832117883638, -544.7848103474569, 0.0),
266                 new OTSPoint3D(-141.88320819563967, -544.7856572416866, 0.0),
267                 new OTSPoint3D(-141.98320346617584, -544.7866291307313, 0.0),
268                 new OTSPoint3D(-142.08319744372974, -544.7877260130723, 0.0),
269                 new OTSPoint3D(-142.1831899720608, -544.7889478869957, 0.0),
270                 new OTSPoint3D(-142.28318089493067, -544.7902947505925, 0.0),
271                 new OTSPoint3D(-142.3831700561036, -544.7917666017579, 0.0),
272                 new OTSPoint3D(-142.48315729934654, -544.7933634381925, 0.0),
273                 new OTSPoint3D(-142.58314246842943, -544.7950852574011, 0.0),
274                 new OTSPoint3D(-142.68312540712546, -544.7969320566932, 0.0),
275                 new OTSPoint3D(-142.78310595921133, -544.7989038331833, 0.0),
276                 new OTSPoint3D(-142.8830839684674, -544.8010005837906, 0.0),
277                 new OTSPoint3D(-142.9830592786781, -544.8032223052389, 0.0),
278                 new OTSPoint3D(-143.08303173363203, -544.8055689940566, 0.0),
279                 new OTSPoint3D(-143.1830011771222, -544.8080406465771, 0.0),
280                 new OTSPoint3D(-143.28296745294642, -544.8106372589384, 0.0),
281                 new OTSPoint3D(-143.3829304049074, -544.8133588270834, 0.0),
282                 new OTSPoint3D(-143.48288987681303, -544.8162053467596, 0.0),
283                 new OTSPoint3D(-143.58284571247668, -544.8191768135193, 0.0),
284                 new OTSPoint3D(-143.68279775571733, -544.8222732227196, 0.0),
285                 new OTSPoint3D(-143.78274585036, -544.8254945695223, 0.0),
286                 new OTSPoint3D(-143.88268984023574, -544.8288408488941, 0.0),
287                 new OTSPoint3D(-143.98262956918217, -544.8323120556064, 0.0),
288                 new OTSPoint3D(-144.0825648810434, -544.8359081842356, 0.0),
289                 new OTSPoint3D(-144.18249561967056, -544.8396292291625, 0.0),
290                 new OTSPoint3D(-144.2824216289219, -544.8434751845731, 0.0),
291                 new OTSPoint3D(-144.38234275266305, -544.847446044458, 0.0),
292                 new OTSPoint3D(-144.48225883476726, -544.8515418026129, 0.0),
293                 new OTSPoint3D(-144.58216971911568, -544.8557624526381, 0.0),
294                 new OTSPoint3D(-144.68207524959763, -544.8601079879389, 0.0),
295                 new OTSPoint3D(-144.7819752701106, -544.8645784017253, 0.0),
296                 new OTSPoint3D(-144.88186962456095, -544.8691736870123, 0.0),
297                 new OTSPoint3D(-144.98175815686372, -544.8738938366197, 0.0),
298                 new OTSPoint3D(-145.0816407109431, -544.8787388431724, 0.0),
299                 new OTSPoint3D(-145.18151713073263, -544.8837086991001, 0.0),
300                 new OTSPoint3D(-145.2813872601755, -544.8888033966373, 0.0),
301                 new OTSPoint3D(-145.3812509432245, -544.8940229278235, 0.0),
302                 new OTSPoint3D(-145.48110802384275, -544.8993672845032, 0.0),
303                 new OTSPoint3D(-145.58095834600357, -544.9048364583259, 0.0),
304                 new OTSPoint3D(-145.68080175369082, -544.9104304407462, 0.0),
305                 new OTSPoint3D(-145.7806380908992, -544.9161492230231, 0.0),
306                 new OTSPoint3D(-145.8804672016345, -544.9219927962213, 0.0),
307                 new OTSPoint3D(-145.98028892991368, -544.9279611512101, 0.0),
308                 new OTSPoint3D(-146.0801031197654, -544.934054278664, 0.0),
309                 new OTSPoint3D(-146.17990961522992, -544.9402721690625, 0.0),
310                 new OTSPoint3D(-146.2797082603597, -544.9466148126901, 0.0),
311                 new OTSPoint3D(-146.37949889921927, -544.9530821996364, 0.0),
312                 new OTSPoint3D(-146.47928137588588, -544.9596743197961, 0.0),
313                 new OTSPoint3D(-146.57905553444937, -544.9663911628691, 0.0),
314                 new OTSPoint3D(-146.67882121901263, -544.9732327183604, 0.0),
315                 new OTSPoint3D(-146.77857827369186, -544.9801989755798, 0.0),
316                 new OTSPoint3D(-146.87832654261663, -544.9872899236427, 0.0),
317                 new OTSPoint3D(-146.97806586993033, -544.9945055514696, 0.0),
318                 new OTSPoint3D(-147.0777960997902, -545.001845847786, 0.0),
319                 new OTSPoint3D(-147.17751707636785, -545.0093108011225, 0.0),
320                 new OTSPoint3D(-147.27722864384927, -545.0169003998153, 0.0),
321                 new OTSPoint3D(-147.37693064643514, -545.0246146320056, 0.0),
322                 new OTSPoint3D(-147.47662292834113, -545.0324534856402, 0.0),
323                 new OTSPoint3D(-147.57630533379802, -545.0404169484702, 0.0),
324                 new OTSPoint3D(-147.67597770705208, -545.0485050080534, 0.0),
325                 new OTSPoint3D(-147.7756398923653, -545.0567176517519, 0.0),
326                 new OTSPoint3D(-147.87529173401546, -545.0650548667334, 0.0),
327                 new OTSPoint3D(-147.97493307629662, -545.0735166399711, 0.0),
328                 new OTSPoint3D(-148.07456376351922, -545.0821029582435, 0.0),
329                 new OTSPoint3D(-148.1741836400103, -545.0908138081345, 0.0),
330                 new OTSPoint3D(-148.27379255011385, -545.0996491760332, 0.0),
331                 new OTSPoint3D(-148.37339033819092, -545.1086090481344, 0.0),
332                 new OTSPoint3D(-148.47297684862002, -545.1176934104385, 0.0),
333                 new OTSPoint3D(-148.57255192579726, -545.1269022487511, 0.0),
334                 new OTSPoint3D(-148.67211541413658, -545.1362355486832, 0.0),
335                 new OTSPoint3D(-148.77166715807007, -545.1456932956519, 0.0),
336                 new OTSPoint3D(-148.87120700204815, -545.1552754748791, 0.0),
337                 new OTSPoint3D(-148.9707347905398, -545.1649820713927, 0.0),
338                 new OTSPoint3D(-149.0702503680329, -545.1748130700264, 0.0),
339                 new OTSPoint3D(-149.16975357903436, -545.1847684554191, 0.0),
340                 new OTSPoint3D(-149.2692442680705, -545.1948482120155, 0.0),
341                 new OTSPoint3D(-149.368722279687, -545.205052324066, 0.0),
342                 new OTSPoint3D(-149.46818745844962, -545.2153807756266, 0.0),
343                 new OTSPoint3D(-149.567639648944, -545.2258335505592, 0.0),
344                 new OTSPoint3D(-149.6670786957761, -545.2364106325315, 0.0),
345                 new OTSPoint3D(-149.76650444357242, -545.2471120050163, 0.0),
346                 new OTSPoint3D(-149.86591673698024, -545.2579376512932, 0.0),
347                 new OTSPoint3D(-149.96531542066793, -545.268887554447, 0.0),
348                 new OTSPoint3D(-150.06470033932501, -545.2799616973684, 0.0),
349                 new OTSPoint3D(-150.1640713376626, -545.2911600627541, 0.0),
350                 new OTSPoint3D(-150.26342826041352, -545.3024826331067, 0.0),
351                 new OTSPoint3D(-150.3627709523326, -545.3139293907345, 0.0),
352                 new OTSPoint3D(-150.46209925819687, -545.3255003177524, 0.0),
353                 new OTSPoint3D(-150.56141302280594, -545.3371953960801, 0.0),
354                 new OTSPoint3D(-150.66071209098203, -545.3490146074447, 0.0),
355                 new OTSPoint3D(-150.7599963075704, -545.3609579333784, 0.0),
356                 new OTSPoint3D(-150.85926551743938, -545.3730253552196, 0.0),
357                 new OTSPoint3D(-150.95851956548103, -545.3852168541134, 0.0),
358                 new OTSPoint3D(-151.05775829661076, -545.3975324110104, 0.0),
359                 new OTSPoint3D(-151.15698155576814, -545.4099720066673, 0.0),
360                 new OTSPoint3D(-151.25618918791685, -545.4225356216475, 0.0),
361                 new OTSPoint3D(-151.35538103804492, -545.4352232363202, 0.0),
362                 new OTSPoint3D(-151.4545569511652, -545.448034830861, 0.0),
363                 new OTSPoint3D(-151.55371677231528, -545.460970385252, 0.0),
364                 new OTSPoint3D(-151.652860346558, -545.4740298792813, 0.0),
365                 new OTSPoint3D(-151.75198751898154, -545.4872132925433, 0.0),
366                 new OTSPoint3D(-151.85109813469967, -545.5005206044389, 0.0),
367                 new OTSPoint3D(-151.95019203885212, -545.5139517941758, 0.0),
368                 new OTSPoint3D(-152.04926907660465, -545.5275068407674, 0.0),
369                 new OTSPoint3D(-152.14832909314944, -545.5411857230341, 0.0),
370                 new OTSPoint3D(-152.24737193370524, -545.5549884196025, 0.0),
371                 new OTSPoint3D(-152.3463974435176, -545.5689149089062, 0.0),
372                 new OTSPoint3D(-152.4454054678592, -545.5829651691847, 0.0),
373                 new OTSPoint3D(-152.54439585203, -545.5971391784847, 0.0),
374                 new OTSPoint3D(-152.64336844135755, -545.6114369146592, 0.0),
375                 new OTSPoint3D(-152.74232308119724, -545.625858355368, 0.0),
376                 new OTSPoint3D(-152.84125961693243, -545.6404034780777, 0.0),
377                 new OTSPoint3D(-152.9401778939748, -545.6550722600615, 0.0),
378                 new OTSPoint3D(-153.03907775776457, -545.6698646783994, 0.0),
379                 new OTSPoint3D(-153.13795905377074, -545.6847807099783, 0.0),
380                 new OTSPoint3D(-153.23682162749128, -545.6998203314919, 0.0),
381                 new OTSPoint3D(-153.33566532445343, -545.7149835194407, 0.0),
382                 new OTSPoint3D(-153.434489990214, -545.7302702501322, 0.0),
383                 new OTSPoint3D(-153.53329547035938, -545.7456804996812, 0.0),
384                 new OTSPoint3D(-153.63208161050608, -545.7612142440088, 0.0),
385                 new OTSPoint3D(-153.73084825630076, -545.7768714588436, 0.0),
386                 new OTSPoint3D(-153.82959525342056, -545.7926521197215, 0.0),
387                 new OTSPoint3D(-153.92832244757332, -545.808556201985, 0.0),
388                 new OTSPoint3D(-154.02702968449785, -545.8245836807839, 0.0),
389                 new OTSPoint3D(-154.12571680996405, -545.8407345310753, 0.0),
390                 new OTSPoint3D(-154.22438366977332, -545.8570087276237, 0.0),
391                 new OTSPoint3D(-154.32303010975875, -545.8734062450004, 0.0),
392                 new OTSPoint3D(-154.42165597578528, -545.8899270575845, 0.0),
393                 new OTSPoint3D(-154.52026111375, -545.9065711395622, 0.0),
394                 new OTSPoint3D(-154.6188453695824, -545.9233384649269, 0.0),
395                 new OTSPoint3D(-154.71740858924463, -545.94022900748, 0.0),
396                 new OTSPoint3D(-154.81595061873168, -545.9572427408298, 0.0),
397                 new OTSPoint3D(-154.91447130407158, -545.9743796383924, 0.0),
398                 new OTSPoint3D(-155.01297049132586, -545.9916396733913, 0.0),
399                 new OTSPoint3D(-155.11144802658953, -546.0090228188579, 0.0),
400                 new OTSPoint3D(-155.20990375599146, -546.026529047631, 0.0),
401                 new OTSPoint3D(-155.3083375256946, -546.044158332357, 0.0),
402                 new OTSPoint3D(-155.4067491818962, -546.0619106454902, 0.0),
403                 new OTSPoint3D(-155.50513857082805, -546.0797859592926, 0.0),
404                 new OTSPoint3D(-155.60350553875676, -546.0977842458342, 0.0),
405                 new OTSPoint3D(-155.701849931984, -546.1159054769923, 0.0),
406                 new OTSPoint3D(-155.8001715968466, -546.1341496244529, 0.0),
407                 new OTSPoint3D(-155.89847037971708, -546.1525166597092, 0.0),
408                 new OTSPoint3D(-155.99674612700352, -546.171006554063, 0.0),
409                 new OTSPoint3D(-156.0949986851501, -546.1896192786236, 0.0),
410                 new OTSPoint3D(-156.19322790063725, -546.2083548043087, 0.0),
411                 new OTSPoint3D(-156.29143361998186, -546.227213101844, 0.0),
412                 new OTSPoint3D(-156.38961568973744, -546.2461941417636, 0.0),
413                 new OTSPoint3D(-156.4877739564946, -546.2652978944094, 0.0),
414                 new OTSPoint3D(-156.585908266881, -546.2845243299319, 0.0),
415                 new OTSPoint3D(-156.68401846756186, -546.3038734182899, 0.0),
416                 new OTSPoint3D(-156.78210440523998, -546.3233451292501, 0.0),
417                 new OTSPoint3D(-156.88016592665613, -546.3429394323884, 0.0),
418                 new OTSPoint3D(-156.97820287858914, -546.3626562970885, 0.0),
419                 new OTSPoint3D(-157.07621510785637, -546.3824956925428, 0.0),
420                 new OTSPoint3D(-157.17420246131368, -546.4024575877521, 0.0),
421                 new OTSPoint3D(-157.27216478585586, -546.4225419515262, 0.0),
422                 new OTSPoint3D(-157.37010192841683, -546.4427487524832, 0.0),
423                 new OTSPoint3D(-157.46801373596978, -546.46307795905, 0.0),
424                 new OTSPoint3D(-157.56590005552755, -546.4835295394621, 0.0),
425                 new OTSPoint3D(-157.66376073414278, -546.504103461764, 0.0),
426                 new OTSPoint3D(-157.76159561890822, -546.524799693809, 0.0),
427                 new OTSPoint3D(-157.8594045569568, -546.5456182032591, 0.0),
428                 new OTSPoint3D(-157.95718739546214, -546.5665589575855, 0.0),
429                 new OTSPoint3D(-158.05494398163856, -546.5876219240682, 0.0),
430                 new OTSPoint3D(-158.15267416274142, -546.6088070697964, 0.0),
431                 new OTSPoint3D(-158.2503777860673, -546.6301143616682, 0.0),
432                 new OTSPoint3D(-158.34805469895434, -546.6515437663911, 0.0),
433                 new OTSPoint3D(-158.44570474878236, -546.6730952504817, 0.0),
434                 new OTSPoint3D(-158.54332778297322, -546.6947687802656, 0.0),
435                 new OTSPoint3D(-158.6409236489909, -546.716564321878, 0.0),
436                 new OTSPoint3D(-158.7384921943419, -546.7384818412634, 0.0),
437                 new OTSPoint3D(-158.83603326657538, -546.7605213041757, 0.0),
438                 new OTSPoint3D(-158.93354671328345, -546.7826826761781, 0.0),
439                 new OTSPoint3D(-159.03103238210136, -546.8049659226436, 0.0),
440                 new OTSPoint3D(-159.1284901207078, -546.8273710087547, 0.0),
441                 new OTSPoint3D(-159.225919776825, -546.8498978995033, 0.0),
442                 new OTSPoint3D(-159.32332119821922, -546.8725465596913, 0.0),
443                 new OTSPoint3D(-159.4206942327007, -546.8953169539299, 0.0),
444                 new OTSPoint3D(-159.51803872812414, -546.9182090466406, 0.0),
445                 new OTSPoint3D(-159.61535453238878, -546.9412228020545, 0.0),
446                 new OTSPoint3D(-159.71264149343864, -546.9643581842125, 0.0),
447                 new OTSPoint3D(-159.80989945926294, -546.9876151569657, 0.0),
448                 new OTSPoint3D(-159.90712827789608, -547.010993683975, 0.0),
449                 new OTSPoint3D(-160.00432779741806, -547.0344937287114, 0.0),
450                 new OTSPoint3D(-160.10149786595466, -547.0581152544562, 0.0),
451                 new OTSPoint3D(-160.19863833167767, -547.0818582243007, 0.0),
452                 new OTSPoint3D(-160.2957490428051, -547.1057226011466, 0.0),
453                 new OTSPoint3D(-160.39282984760155, -547.1297083477057, 0.0),
454                 new OTSPoint3D(-160.4898805943782, -547.1538154265004, 0.0),
455                 new OTSPoint3D(-160.58690113149333, -547.1780437998632, 0.0),
456                 new OTSPoint3D(-160.68389130735238, -547.2023934299375, 0.0),
457                 new OTSPoint3D(-160.78085097040818, -547.2268642786769, 0.0),
458                 new OTSPoint3D(-160.87777996916128, -547.2514563078457, 0.0),
459                 new OTSPoint3D(-160.97467815216018, -547.2761694790188, 0.0),
460                 new OTSPoint3D(-161.07154536800144, -547.3010037535821, 0.0),
461                 new OTSPoint3D(-161.1683814653301, -547.3259590927318, 0.0),
462                 new OTSPoint3D(-161.26518629283973, -547.3510354574753, 0.0),
463                 new OTSPoint3D(-161.36195969927286, -547.3762328086307, 0.0),
464                 new OTSPoint3D(-161.45870153342102, -547.4015511068272, 0.0),
465                 new OTSPoint3D(-161.55541164412512, -547.426990312505, 0.0),
466                 new OTSPoint3D(-161.65208988027564, -547.4525503859154, 0.0),
467                 new OTSPoint3D(-161.74873609081288, -547.4782312871207, 0.0),
468                 new OTSPoint3D(-161.8453501247271, -547.5040329759945, 0.0),
469                 new OTSPoint3D(-161.94193183105892, -547.5299554122216, 0.0),
470                 new OTSPoint3D(-162.0384810588995, -547.5559985552984, 0.0),
471                 new OTSPoint3D(-162.13499765739058, -547.5821623645322, 0.0),
472                 new OTSPoint3D(-162.23148147572508, -547.6084467990423, 0.0),
473                 new OTSPoint3D(-162.327932363147, -547.6348518177593, 0.0),
474                 new OTSPoint3D(-162.4243501689519, -547.6613773794252, 0.0),
475                 new OTSPoint3D(-162.52073474248692, -547.6880234425938, 0.0),
476                 new OTSPoint3D(-162.61708593315126, -547.7147899656309, 0.0),
477                 new OTSPoint3D(-162.71340359039613, -547.7416769067133, 0.0),
478                 new OTSPoint3D(-162.80968756372525, -547.7686842238307, 0.0),
479                 new OTSPoint3D(-162.9059377026949, -547.795811874784, 0.0),
480                 new OTSPoint3D(-163.0021538569143, -547.8230598171862, 0.0),
481                 new OTSPoint3D(-163.0983358760457, -547.8504280084622, 0.0),
482                 new OTSPoint3D(-163.1944836098047, -547.8779164058496, 0.0),
483                 new OTSPoint3D(-163.29059690796055, -547.9055249663976, 0.0),
484                 new OTSPoint3D(-163.38667562033615, -547.9332536469677, 0.0),
485                 new OTSPoint3D(-163.4827195968086, -547.961102404234, 0.0),
486                 new OTSPoint3D(-163.5787286873092, -547.9890711946829, 0.0),
487                 new OTSPoint3D(-163.67470274182375, -548.0171599746129, 0.0),
488                 new OTSPoint3D(-163.7706416103928, -548.0453687001356, 0.0),
489                 new OTSPoint3D(-163.8665451431119, -548.0736973271746, 0.0),
490                 new OTSPoint3D(-163.96241319013177, -548.1021458114666, 0.0),
491                 new OTSPoint3D(-164.05824560165868, -548.1307141085607, 0.0),
492                 new OTSPoint3D(-164.15404222795442, -548.1594021738192, 0.0),
493                 new OTSPoint3D(-164.24980291933684, -548.1882099624167, 0.0),
494                 new OTSPoint3D(-164.34552752617986, -548.2171374293412, 0.0),
495                 new OTSPoint3D(-164.4412158989138, -548.2461845293935, 0.0),
496                 new OTSPoint3D(-164.53686788802563, -548.2753512171876, 0.0),
497                 new OTSPoint3D(-164.63248334405907, -548.3046374471504, 0.0),
498                 new OTSPoint3D(-164.72806211761502, -548.3340431735223, 0.0),
499                 new OTSPoint3D(-164.82360405935168, -548.3635683503568, 0.0),
500                 new OTSPoint3D(-164.91910901998477, -548.3932129315208, 0.0),
501                 new OTSPoint3D(-165.01457685028782, -548.4229768706948, 0.0),
502                 new OTSPoint3D(-165.11000740109236, -548.4528601213724, 0.0),
503                 new OTSPoint3D(-165.20540052328818, -548.4828626368612, 0.0),
504                 new OTSPoint3D(-165.30075606782353, -548.5129843702822, 0.0),
505                 new OTSPoint3D(-165.3960738857054, -548.5432252745702, 0.0),
506                 new OTSPoint3D(-165.49135382799972, -548.5735853024739, 0.0),
507                 new OTSPoint3D(-165.58659574583157, -548.6040644065556, 0.0),
508                 new OTSPoint3D(-165.68179949038554, -548.6346625391919, 0.0),
509                 new OTSPoint3D(-165.77696491290575, -548.665379652573, 0.0),
510                 new OTSPoint3D(-165.87209186469624, -548.6962156987037, 0.0),
511                 new OTSPoint3D(-165.9671801971212, -548.7271706294023, 0.0),
512                 new OTSPoint3D(-166.06222976160512, -548.7582443963021, 0.0),
513                 new OTSPoint3D(-166.15724040963306, -548.7894369508501, 0.0),
514                 new OTSPoint3D(-166.2522119927509, -548.8207482443081, 0.0),
515                 new OTSPoint3D(-166.34714436256556, -548.852178227752, 0.0),
516                 new OTSPoint3D(-166.44203737074525, -548.8837268520728, 0.0),
517                 new OTSPoint3D(-166.5368908690197, -548.9153940679754, 0.0),
518                 new OTSPoint3D(-166.63170470918024, -548.94717982598, 0.0),
519                 new OTSPoint3D(-166.72647874308035, -548.9790840764214, 0.0),
520                 new OTSPoint3D(-166.82121282263557, -549.011106769449, 0.0),
521                 new OTSPoint3D(-166.91590679982392, -549.0432478550275, 0.0),
522                 new OTSPoint3D(-167.01056052668613, -549.0755072829365, 0.0),
523                 new OTSPoint3D(-167.10517385532575, -549.1078850027706, 0.0),
524                 new OTSPoint3D(-167.19974663790944, -549.1403809639396, 0.0),
525                 new OTSPoint3D(-167.29427872666727, -549.1729951156685, 0.0),
526                 new OTSPoint3D(-167.3887699738929, -549.2057274069979, 0.0),
527                 new OTSPoint3D(-167.4832202319437, -549.2385777867835, 0.0),
528                 new OTSPoint3D(-167.57762935324124, -549.2715462036964, 0.0),
529                 new OTSPoint3D(-167.67199719027124, -549.3046326062237, 0.0),
530                 new OTSPoint3D(-167.766323595584, -549.3378369426678, 0.0),
531                 new OTSPoint3D(-167.86060842179452, -549.3711591611469, 0.0),
532                 new OTSPoint3D(-167.95485152158278, -549.4045992095952, 0.0),
533                 new OTSPoint3D(-168.04905274769393, -549.4381570357625, 0.0),
534                 new OTSPoint3D(-168.1432119529386, -549.4718325872147, 0.0),
535                 new OTSPoint3D(-168.23732899019308, -549.5056258113337, 0.0),
536                 new OTSPoint3D(-168.33140371239944, -549.5395366553179, 0.0),
537                 new OTSPoint3D(-168.42543597256602, -549.5735650661812, 0.0),
538                 new OTSPoint3D(-168.5194256237674, -549.6077109907545, 0.0),
539                 new OTSPoint3D(-168.61337251914478, -549.6419743756846, 0.0),
540                 new OTSPoint3D(-168.70727651190614, -549.6763551674352, 0.0),
541                 new OTSPoint3D(-168.8011374553265, -549.7108533122862, 0.0),
542                 new OTSPoint3D(-168.8949552027482, -549.7454687563342, 0.0),
543                 new OTSPoint3D(-168.988729607581, -549.7802014454926, 0.0),
544                 new OTSPoint3D(-169.08246052330242, -549.8150513254916, 0.0),
545                 new OTSPoint3D(-169.1761478034579, -549.8500183418782, 0.0),
546                 new OTSPoint3D(-169.2697913016611, -549.8851024400167, 0.0),
547                 new OTSPoint3D(-169.36339087159408, -549.9203035650879, 0.0),
548                 new OTSPoint3D(-169.45694636700753, -549.9556216620903, 0.0),
549                 new OTSPoint3D(-169.55045764172098, -549.9910566758391, 0.0),
550                 new OTSPoint3D(-169.64392454962314, -550.0266085509672, 0.0),
551                 new OTSPoint3D(-169.73734694467194, -550.062277231925, 0.0),
552                 new OTSPoint3D(-169.8307246808949, -550.09806266298, 0.0),
553                 new OTSPoint3D(-169.92405761238936, -550.1339647882176, 0.0),
554                 new OTSPoint3D(-170.0173455933226, -550.1699835515406, 0.0),
555                 new OTSPoint3D(-170.1105884779322, -550.2061188966698, 0.0),
556                 new OTSPoint3D(-170.20378612052616, -550.2423707671435, 0.0),
557                 new OTSPoint3D(-170.29693837548317, -550.2787391063184, 0.0),
558                 new OTSPoint3D(-170.39004509725288, -550.315223857369, 0.0),
559                 new OTSPoint3D(-170.48310614035597, -550.3518249632878, 0.0),
560                 new OTSPoint3D(-170.57612135938473, -550.3885423668855, 0.0),
561                 new OTSPoint3D(-170.66909060900278, -550.4253760107913, 0.0),
562                 new OTSPoint3D(-170.76201374394572, -550.4623258374525, 0.0),
563                 new OTSPoint3D(-170.85489061902118, -550.4993917891351, 0.0),
564                 new OTSPoint3D(-170.94772108910905, -550.5365738079236, 0.0),
565                 new OTSPoint3D(-171.04050500916173, -550.573871835721, 0.0),
566                 new OTSPoint3D(-171.13324223420437, -550.6112858142492, 0.0),
567                 new OTSPoint3D(-171.2259326193351, -550.6488156850488, 0.0),
568                 new OTSPoint3D(-171.3185760197252, -550.6864613894795, 0.0),
569                 new OTSPoint3D(-171.4111722906194, -550.7242228687198, 0.0),
570                 new OTSPoint3D(-171.50372128733594, -550.7621000637674, 0.0),
571                 new OTSPoint3D(-171.59622286526712, -550.8000929154392, 0.0),
572                 new OTSPoint3D(-171.68867687987927, -550.8382013643715, 0.0),
573                 new OTSPoint3D(-171.78108318671295, -550.8764253510196, 0.0),
574                 new OTSPoint3D(-171.8734416413833, -550.9147648156588, 0.0),
575                 new OTSPoint3D(-171.96575209958038, -550.9532196983835, 0.0),
576                 new OTSPoint3D(-172.058014417069, -550.991789939108, 0.0),
577                 new OTSPoint3D(-183.2636723755513, -556.3855708716345, 0.0),
578                 new OTSPoint3D(-183.7248063744403, -556.6224974422428, 0.0),
579                 new OTSPoint3D(-184.4647247962342, -557.0026609839204, 0.0),
580                 new OTSPoint3D(-186.64575105571316, -558.2116382472677, 0.0));
581         System.out.println("AV line3:                                           " + checkAll(reference, 1.625));
582 
583         System.out.println("Test complete.");
584 
585         /*-
586         int i = 8;
587         
588         switch (i)
589         {
590             case 1:
591                 test1();
592                 break;
593             case 2:
594                 test2();
595                 break;
596             case 3:
597                 test3();
598                 break;
599             case 4:
600                 test4();
601                 break;
602             case 5:
603                 test5();
604                 break;
605             case 6:
606                 test6();
607                 break;
608             case 7:
609                 test7();
610                 break;
611             case 8:
612                 test8();
613                 break;
614         }
615          */
616     }
617 
618     /** Print detailed output. */
619     static boolean printDetails = false;
620 
621     /**
622      * Construct parallel line.
623      * @param referenceLine OTSLine3D; the reference line
624      * @param offset double; the offset
625      * @param offsetMethod OTSLine3D.OffsetMethod; the offset method
626      * @return OTSLine3D; the line that has the specified offset from the reference line
627      */
628     private static OTSLine3D offsetLine(final OTSLine3D referenceLine, final double offset,
629             final OTSLine3D.OffsetMethod offsetMethod)
630     {
631         try
632         {
633             switch (offsetMethod)
634             {
635                 case PK:
636                     return OTSOffsetLinePK.offsetLine(referenceLine, offset);
637 
638                 case JTS:
639                     return OTSBufferingJTS.offsetGeometryOLD(referenceLine, offset);
640 
641                 default:
642                     return null;
643             }
644         }
645         catch (OTSGeometryException exception)
646         {
647             exception.printStackTrace();
648             return null;
649         }
650     }
651 
652     /**
653      * Check the offsetLine method.
654      * @param referenceLine OTSLine3D; the reference line
655      * @param offset double; the offset
656      * @param offsetMethod OTSLine3D.OffsetMethod; the offset method
657      * @return boolean; false if the result is obviously wrong; true if the result (appears to be) fine
658      */
659     public static boolean checkOffsetLine(final OTSLine3D referenceLine, final double offset,
660             final OTSLine3D.OffsetMethod offsetMethod)
661     {
662         double absOffset = Math.abs(offset);
663         double maxErrorFar = 0.01;
664         double maxErrorClose = 0.002;
665         try
666         {
667             OTSLine3D offsetLine = offsetLine(referenceLine, offset, offsetMethod);
668             if (null == offsetLine)
669             {
670                 if (printDetails)
671                 {
672                     System.out.println(String.format(Locale.US, "#offset %7.3f, method %3.3s returned null referenceLine %s",
673                             offset, offsetMethod, referenceLine));
674                 }
675                 return false;
676             }
677             // Walk the length of the reference line in small steps.
678             final int numSteps = 1000;
679             double[] closestToResult = new double[numSteps + 1];
680             double[] closestToReference = new double[numSteps + 1];
681             for (int i = 0; i < closestToResult.length; i++)
682             {
683                 closestToResult[i] = Double.MAX_VALUE;
684                 closestToReference[i] = Double.MAX_VALUE;
685             }
686             double referenceLength = referenceLine.getLengthSI();
687             double resultLength = offsetLine.getLengthSI();
688             double resultEndFirst = offsetLine.getFirst().distanceSI(offsetLine.get(1));
689             double resultStartLast =
690                     offsetLine.getLengthSI() - offsetLine.getLast().distanceSI(offsetLine.get(offsetLine.size() - 2));
691             for (int referenceStep = 0; referenceStep < numSteps + 1; referenceStep++)
692             {
693                 double referencePosition = referenceLength * referenceStep / numSteps;
694                 OTSPoint3D referencePoint = new OTSPoint3D(referenceLine.getLocationExtendedSI(referencePosition));
695                 for (int resultStep = 0; resultStep < numSteps + 1; resultStep++)
696                 {
697                     double resultPosition = resultLength * resultStep / numSteps;
698                     OTSPoint3D resultPoint = new OTSPoint3D(offsetLine.getLocationExtendedSI(resultPosition));
699                     double distance = referencePoint.horizontalDistanceSI(resultPoint);
700                     if (distance <= absOffset)
701                     {
702                         if (resultPosition <= resultEndFirst)
703                         {
704                             continue;
705                         }
706                         if (resultPosition >= resultStartLast)
707                         {
708                             continue;
709                         }
710                     }
711                     if (distance < closestToResult[resultStep])
712                     {
713                         closestToResult[resultStep] = distance;
714                     }
715                     if (distance < closestToReference[referenceStep])
716                     {
717                         closestToReference[referenceStep] = distance;
718                     }
719                 }
720             }
721             int referenceTooClose = 0;
722             int resultTooClose = 0;
723             int resultTooFar = 0;
724             for (int i = 0; i < closestToResult.length; i++)
725             {
726                 if (closestToResult[i] > absOffset + maxErrorFar)
727                 {
728                     resultTooFar++;
729                 }
730                 if (closestToResult[i] < absOffset - maxErrorClose)
731                 {
732                     resultTooClose++;
733                 }
734                 if (closestToReference[i] < absOffset - maxErrorClose)
735                 {
736                     referenceTooClose++;
737                 }
738             }
739             if (0 == referenceTooClose && 0 == resultTooClose && 0 == resultTooFar)
740             {
741                 if (printDetails)
742                 {
743                     System.out.println("#No errors detected");
744                     System.out.println(OTSGeometryUtil.printCoordinates("#reference: \nc1,0,0\n#", referenceLine, "\n    "));
745                     System.out.println(OTSGeometryUtil.printCoordinates("#offset: \nc0,1,0\n#", offsetLine, "\n    "));
746                 }
747                 return true;
748             }
749             double factor = 100d / (numSteps + 1);
750             if (printDetails)
751             {
752                 System.out.println(String.format(Locale.US,
753                         "#offset %7.3f, method %3.3s: result line too close for %5.1f%%, "
754                                 + "too far for %5.1f%%, reference too close for %5.1f%%",
755                         offset, offsetMethod, resultTooClose * factor, resultTooFar * factor, referenceTooClose * factor));
756                 for (int i = 0; i < closestToReference.length; i++)
757                 {
758                     if (closestToReference[i] > absOffset + maxErrorFar)
759                     {
760                         DirectedPoint p = referenceLine.getLocationSI(i * referenceLength / numSteps);
761                         System.out.println(String.format("sc0.7,0.7,0.7w0.2M%.3f,%.3fl0,0r", p.x, p.y));
762                     }
763                 }
764                 for (int i = 0; i < closestToResult.length; i++)
765                 {
766                     if (closestToResult[i] > absOffset + maxErrorFar || closestToResult[i] < absOffset - maxErrorClose)
767                     {
768                         DirectedPoint p = offsetLine.getLocationSI(i * resultLength / numSteps);
769                         System.out.println(String.format("sw0.2M%.3f,%.3fl0,0r", p.x, p.y));
770                     }
771                 }
772                 System.out.println(OTSGeometryUtil.printCoordinates("#reference: \nc1,0,0\n#", referenceLine, "\n    "));
773                 System.out.println(OTSGeometryUtil.printCoordinates("#offset: \nc0,1,0\n#", offsetLine, "\n    "));
774             }
775             return false;
776         }
777         catch (OTSGeometryException exception)
778         {
779             System.err.println("Caught unexpected exception.");
780             exception.printStackTrace();
781             return false;
782         }
783     }
784 
785     /**
786      * Kink near end of design line.
787      * @throws OTSGeometryException on error
788      */
789     public static void test1() throws OTSGeometryException
790     {
791         System.out.println("Dcirc,sm-2,0a2,0,360r");
792         System.out.println("M5.0,2.5dcirc");
793         System.out.println("M4.8,2.5dcirc");
794         System.out.println("M4.6,2.7dcirc");
795         System.out.println("M2.2,2.7dcirc");
796         System.out.println("M2.2,5dcirc");
797         System.out.println("");
798         OTSLine3D referenceLine = new OTSLine3D(new OTSPoint3D(5, 2.5), new OTSPoint3D(4.8, 2.5), new OTSPoint3D(4.6, 2.7),
799                 new OTSPoint3D(2.2, 2.7), new OTSPoint3D(2.2, 5));
800         System.out.println(OTSGeometryUtil.printCoordinates("#reference line: \nc1,0,0\n#", referenceLine, "\n    "));
801         // OTSLine3D.debugOffsetLine = true;
802         OTSLine3D left = referenceLine.offsetLine(2.0);
803         System.out.println(OTSGeometryUtil.printCoordinates("#left: \nc0,1,0\n#", left, "\n   "));
804         OTSLine3D right = referenceLine.offsetLine(-2.0);
805         System.out.println(OTSGeometryUtil.printCoordinates("#right: \nc0,1,0\n#", right, "\n   "));
806     }
807 
808     /**
809      * Kink halfway (far from any endpoint).
810      * @throws OTSGeometryException on error
811      */
812     public static void test2() throws OTSGeometryException
813     {
814         OTSLine3D otsLine = new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(10, 5, 0), new OTSPoint3D(20, 0, 0));
815         System.out.println(OTSGeometryUtil.printCoordinates("#reference line: \nc1,0,0\n#", otsLine, "\n    "));
816         OTSLine3D left = otsLine.offsetLine(2.0);
817         System.out.println(OTSGeometryUtil.printCoordinates("#left: \nc0,1,0\n#", left, "\n   "));
818         OTSLine3D right = otsLine.offsetLine(-2.0);
819         System.out.println(OTSGeometryUtil.printCoordinates("#buffer: \nc0,1,0\n#", right, "\n   "));
820     }
821 
822     /**
823      * Kink plus decreasing width.
824      * @throws OTSGeometryException on error
825      */
826     public static void test3() throws OTSGeometryException
827     {
828         OTSLine3D referenceLine =
829                 new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(200, 100, 0), new OTSPoint3D(1000, 0, 0));
830         System.out.println(OTSGeometryUtil.printCoordinates("#reference line: \nc1,0,0\n#", referenceLine, "\n    "));
831         OTSLine3D centerLine = referenceLine.offsetLine(-8, -5);
832         System.out.println(OTSGeometryUtil.printCoordinates("#center line: \nc0,1,0\n#", centerLine, "\n   "));
833         for (int i = 1; i < centerLine.size(); i++)
834         {
835             OTSPoint3D from = centerLine.get(i - 1);
836             OTSPoint3D to = centerLine.get(i);
837             double angle = Math.atan2(to.y - from.y, to.x - from.x);
838             System.out.println("#Direction in segment " + i + " is " + Math.toDegrees(angle));
839         }
840         OTSLine3D leftEdge = centerLine.offsetLine(1.5, 2);
841         System.out.println(OTSGeometryUtil.printCoordinates("#left edge: \nc0,0,1\n#", leftEdge, "\n   "));
842         OTSLine3D rightEdge = centerLine.offsetLine(-1.5, -2);
843         System.out.println(OTSGeometryUtil.printCoordinates("#right edge: \nc0,0,1\n#", rightEdge, "\n   "));
844     }
845 
846     /**
847      * Two kinks, (too) close together.
848      * @throws OTSGeometryException on error
849      */
850     public static void test4() throws OTSGeometryException
851     {
852         OTSLine3D reference = new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(20, 10, 0), new OTSPoint3D(21, 10, 0),
853                 new OTSPoint3D(22, 9.5, 0), new OTSPoint3D(30, 0, 0));
854         System.out.println(OTSGeometryUtil.printCoordinates("#reference: \nc1,0,0\n#", reference, "\n    "));
855         OTSLine3D offset = reference.offsetLine(-3);
856         System.out.println(OTSGeometryUtil.printCoordinates("#offset: \nc0,1,0\n#", offset, "\n    "));
857     }
858 
859     /**
860      * Two-segment design line with minimal change of direction.
861      * @throws OTSGeometryException on error
862      */
863     public static void test5() throws OTSGeometryException
864     {
865         OTSPoint3D[] designLinePoints = new OTSPoint3D[8];
866         double radius = 10;
867         double angleStep = Math.PI / 1000;
868         double initialAngle = Math.PI / 4;
869         for (int i = 0; i < designLinePoints.length; i++)
870         {
871             double angle = initialAngle + i * angleStep;
872             designLinePoints[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle) - radius, 0);
873         }
874         // OTSLine3D.debugOffsetLine = true;
875         OTSLine3D reference = new OTSLine3D(designLinePoints);
876         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
877         OTSLine3D centerLine = reference.offsetLine(5);
878         System.out.println(OTSGeometryUtil.printCoordinates("#center:\nc0,1,0\n#", centerLine, "\n    "));
879         for (int i = 1; i < centerLine.size() - 1; i++)
880         {
881             // double distance =
882             // centerLine.get(i).horizontalDistanceToLineSegment(centerLine.get(0), centerLine.get(centerLine.size() - 1));
883             double distance = centerLine.get(i)
884                     .closestPointOnLine2D(new OTSLine3D(centerLine.get(0), centerLine.get(centerLine.size() - 1)))
885                     .horizontalDistanceSI(centerLine.get(i));
886             System.out.println("#distance of intermediate point " + i + " to overall line is " + distance);
887         }
888         OTSLine3D right = centerLine.offsetLine(-2);
889         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
890         OTSLine3D left = centerLine.offsetLine(2);
891         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
892     }
893 
894     /**
895      * Straight design line with some <i>noise</i> (sufficiently far from the end points).
896      * @throws OTSGeometryException on error
897      */
898     public static void test6() throws OTSGeometryException
899     {
900         System.out.println("O0,-10");
901         OTSLine3D reference =
902                 new OTSLine3D(new OTSPoint3D(10, 10, 0), new OTSPoint3D(9.999, 8, 0), new OTSPoint3D(9.996, 7.99, 0),
903                         new OTSPoint3D(9.999, 7.98, 0), new OTSPoint3D(10.03, 7.95, 0), new OTSPoint3D(10.01, 7.94, 0),
904                         new OTSPoint3D(10.0, 7.94, 0), new OTSPoint3D(10, 6, 0), new OTSPoint3D(10, 2, 0));
905         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
906         OTSLine3D right = reference.offsetLine(-2);
907         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
908         OTSLine3D left = reference.offsetLine(2);
909         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
910     }
911 
912     /**
913      * Straight design line with more <i>noise</i> (sufficiently far from the end points).
914      * @throws OTSGeometryException on error
915      */
916     public static void test7() throws OTSGeometryException
917     {
918         System.out.println("O0,-10");
919         OTSLine3D reference =
920                 new OTSLine3D(new OTSPoint3D(10, 10, 0), new OTSPoint3D(9.999, 8, 0), new OTSPoint3D(9.996, 7.99, 0),
921                         new OTSPoint3D(9.999, 7.98, 0), new OTSPoint3D(10.03, 7.95, 0), new OTSPoint3D(10.01, 7.94, 0),
922                         new OTSPoint3D(10.0, 7.94, 0), new OTSPoint3D(10, 6, 0), new OTSPoint3D(9.999, 6, 0),
923                         new OTSPoint3D(9.996, 5.99, 0), new OTSPoint3D(9.999, 5.98, 0), new OTSPoint3D(10.03, 5.95, 0),
924                         new OTSPoint3D(10.01, 5.94, 0), new OTSPoint3D(10.0, 5.94, 0), new OTSPoint3D(10, 2, 0));
925 
926         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
927         OTSLine3D right = reference.offsetLine(-2);
928         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
929         OTSLine3D left = reference.offsetLine(2);
930         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
931     }
932 
933     /**
934      * Straight design line with more <i>noise</i> (close to the end points).
935      * @throws OTSGeometryException on error
936      */
937     public static void test8() throws OTSGeometryException
938     {
939         // System.out.println("O0,-10");
940         // OTSLine3D reference =
941         // new OTSLine3D(new OTSPoint3D(10, 9, 0), new OTSPoint3D(9.999, 8, 0), new OTSPoint3D(9.996, 7.99, 0),
942         // new OTSPoint3D(9.999, 7.98, 0), new OTSPoint3D(10.03, 7.95, 0), new OTSPoint3D(10.01, 7.94, 0),
943         // new OTSPoint3D(10.0, 7.94, 0), new OTSPoint3D(10, 6, 0), new OTSPoint3D(9.999, 6, 0), new OTSPoint3D(
944         // 9.996, 5.99, 0), new OTSPoint3D(9.999, 5.98, 0), new OTSPoint3D(10.03, 5.95, 0),
945         // new OTSPoint3D(10.01, 5.94, 0), new OTSPoint3D(10.0, 5.94, 0), new OTSPoint3D(10, 5, 0));
946         OTSLine3D reference = new OTSLine3D(new OTSPoint3D(5, -1, 0), new OTSPoint3D(5, -2, 0), new OTSPoint3D(4.9, -2.01, 0),
947                 new OTSPoint3D(5.1, -2.03, 0), new OTSPoint3D(5, -2.04, 0), new OTSPoint3D(5, -6, 0),
948                 new OTSPoint3D(4.9, -6.01, 0), new OTSPoint3D(5.1, -6.03, 0), new OTSPoint3D(5, -6.04, 0),
949                 new OTSPoint3D(5, -7.04, 0));
950 
951         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
952         OTSLine3D right = reference.offsetLine(-2);
953         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
954         OTSLine3D left = reference.offsetLine(2);
955         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
956 
957         reference = new OTSLine3D(new OTSPoint3D(10, 0.5, 0), new OTSPoint3D(10, -2, 0), new OTSPoint3D(9.9, -2.01, 0),
958                 new OTSPoint3D(10.1, -2.03, 0), new OTSPoint3D(10, -2.04, 0), new OTSPoint3D(10, -6, 0),
959                 new OTSPoint3D(9.9, -6.01, 0), new OTSPoint3D(10.1, -6.03, 0), new OTSPoint3D(10, -6.04, 0),
960                 new OTSPoint3D(10, -8.54, 0));
961 
962         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
963         right = reference.offsetLine(-2);
964         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
965         left = reference.offsetLine(2);
966         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
967     }
968 
969     /**
970      * Stolen from <a href="http://www.journaldev.com/1650/java-futuretask-example-program">
971      * http://www.journaldev.com/1650/java-futuretask-example-program</a>.
972      */
973     class MyCallable implements Callable<String>, Serializable
974     {
975         /** */
976         private static final long serialVersionUID = 20170400L;
977 
978         /** The reference line. */
979         private final OTSLine3D referenceLine;
980 
981         /** The offset. */
982         private final double offset;
983 
984         /** The offset method. */
985         private final OTSLine3D.OffsetMethod offsetMethod;
986 
987         /**
988          * Construct a MyCallable object.
989          * @param referenceLine OTSLine3D; the reference line
990          * @param offset double; the offset
991          * @param offsetMethod OTSLine3D.OffsetMethod; the offset method
992          */
993         MyCallable(final OTSLine3D referenceLine, final double offset, final OTSLine3D.OffsetMethod offsetMethod)
994         {
995             this.referenceLine = referenceLine;
996             this.offset = offset;
997             this.offsetMethod = offsetMethod;
998         }
999 
1000         /** {@inheritDoc} */
1001         @Override
1002         public String call() throws Exception
1003         {
1004             if (checkOffsetLine(this.referenceLine, this.offset, this.offsetMethod))
1005             {
1006                 return "OK";
1007             }
1008             return "fail";
1009         }
1010 
1011         /** {@inheritDoc} */
1012         @Override
1013         public final String toString()
1014         {
1015             return "MyCallable [referenceLine=" + this.referenceLine + ", offset=" + this.offset + ", offsetMethod="
1016                     + this.offsetMethod + "]";
1017         }
1018 
1019     }
1020 
1021 }