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