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