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