View Javadoc
1   package org.opentrafficsim.core.geometry;
2   
3   import java.util.Locale;
4   import java.util.concurrent.Callable;
5   import java.util.concurrent.ExecutionException;
6   import java.util.concurrent.ExecutorService;
7   import java.util.concurrent.Executors;
8   import java.util.concurrent.FutureTask;
9   import java.util.concurrent.TimeUnit;
10  import java.util.concurrent.TimeoutException;
11  
12  import nl.tudelft.simulation.language.d3.DirectedPoint;
13  
14  import org.jfree.ui.HorizontalAlignment;
15  import org.opentrafficsim.core.network.NetworkException;
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, OTSLine3D.OffsetMethod.AV })
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 AV:
502                     return OTSBufferingAV.offsetLine(referenceLine, offset);
503 
504                 case JTS:
505                     return OTSBufferingJTS.offsetGeometryOLD(referenceLine, offset);
506 
507                 default:
508                     return null;
509             }
510         }
511         catch (OTSGeometryException exception)
512         {
513             exception.printStackTrace();
514             return null;
515         }
516     }
517 
518     /**
519      * Check the offsetLine method.
520      * @param referenceLine OTSLine3D; the reference line
521      * @param offset double; the offset
522      * @param offsetMethod OTSLine3D.OffsetMethod; the offset method
523      * @return boolean; false if the result is obviously wrong; true if the result (appears to be) fine
524      */
525     public static boolean checkOffsetLine(final OTSLine3D referenceLine, final double offset,
526             final OTSLine3D.OffsetMethod offsetMethod)
527     {
528         double absOffset = Math.abs(offset);
529         double maxErrorFar = 0.01;
530         double maxErrorClose = 0.002;
531         try
532         {
533             OTSLine3D offsetLine = offsetLine(referenceLine, offset, offsetMethod);
534             if (null == offsetLine)
535             {
536                 if (printDetails)
537                 {
538                     System.out.println(String.format(Locale.US, "#offset %7.3f, method %3.3s returned null referenceLine %s",
539                             offset, offsetMethod, referenceLine));
540                 }
541                 return false;
542             }
543             // Walk the length of the reference line in small steps.
544             final int numSteps = 1000;
545             double[] closestToResult = new double[numSteps + 1];
546             double[] closestToReference = new double[numSteps + 1];
547             for (int i = 0; i < closestToResult.length; i++)
548             {
549                 closestToResult[i] = Double.MAX_VALUE;
550                 closestToReference[i] = Double.MAX_VALUE;
551             }
552             double referenceLength = referenceLine.getLengthSI();
553             double resultLength = offsetLine.getLengthSI();
554             double resultEndFirst = offsetLine.getFirst().distanceSI(offsetLine.get(1));
555             double resultStartLast =
556                     offsetLine.getLengthSI() - offsetLine.getLast().distanceSI(offsetLine.get(offsetLine.size() - 2));
557             for (int referenceStep = 0; referenceStep < numSteps + 1; referenceStep++)
558             {
559                 double referencePosition = referenceLength * referenceStep / numSteps;
560                 OTSPoint3D referencePoint = new OTSPoint3D(referenceLine.getLocationExtendedSI(referencePosition));
561                 for (int resultStep = 0; resultStep < numSteps + 1; resultStep++)
562                 {
563                     double resultPosition = resultLength * resultStep / numSteps;
564                     OTSPoint3D resultPoint = new OTSPoint3D(offsetLine.getLocationExtendedSI(resultPosition));
565                     double distance = referencePoint.horizontalDistanceSI(resultPoint);
566                     if (distance <= absOffset)
567                     {
568                         if (resultPosition <= resultEndFirst)
569                         {
570                             continue;
571                         }
572                         if (resultPosition >= resultStartLast)
573                         {
574                             continue;
575                         }
576                     }
577                     if (distance < closestToResult[resultStep])
578                     {
579                         closestToResult[resultStep] = distance;
580                     }
581                     if (distance < closestToReference[referenceStep])
582                     {
583                         closestToReference[referenceStep] = distance;
584                     }
585                 }
586             }
587             int referenceTooClose = 0;
588             int resultTooClose = 0;
589             int resultTooFar = 0;
590             for (int i = 0; i < closestToResult.length; i++)
591             {
592                 if (closestToResult[i] > absOffset + maxErrorFar)
593                 {
594                     resultTooFar++;
595                 }
596                 if (closestToResult[i] < absOffset - maxErrorClose)
597                 {
598                     resultTooClose++;
599                 }
600                 if (closestToReference[i] < absOffset - maxErrorClose)
601                 {
602                     referenceTooClose++;
603                 }
604             }
605             if (0 == referenceTooClose && 0 == resultTooClose && 0 == resultTooFar)
606             {
607                 if (printDetails)
608                 {
609                     System.out.println("#No errors detected");
610                     System.out.println(OTSGeometryUtil.printCoordinates("#reference: \nc1,0,0\n#", referenceLine, "\n    "));
611                     System.out.println(OTSGeometryUtil.printCoordinates("#offset: \nc0,1,0\n#", offsetLine, "\n    "));
612                 }
613                 return true;
614             }
615             double factor = 100d / (numSteps + 1);
616             if (printDetails)
617             {
618                 System.out.println(String.format(Locale.US, "#offset %7.3f, method %3.3s: result line too close for %5.1f%%, "
619                         + "too far for %5.1f%%, reference too close for %5.1f%%", offset, offsetMethod,
620                         resultTooClose * factor, resultTooFar * factor, referenceTooClose * factor));
621                 for (int i = 0; i < closestToReference.length; i++)
622                 {
623                     if (closestToReference[i] > absOffset + maxErrorFar)
624                     {
625                         DirectedPoint p = referenceLine.getLocationSI(i * referenceLength / numSteps);
626                         System.out.println(String.format("sc0.7,0.7,0.7w0.2M%.3f,%.3fl0,0r", p.x, p.y));
627                     }
628                 }
629                 for (int i = 0; i < closestToResult.length; i++)
630                 {
631                     if (closestToResult[i] > absOffset + maxErrorFar || closestToResult[i] < absOffset - maxErrorClose)
632                     {
633                         DirectedPoint p = offsetLine.getLocationSI(i * resultLength / numSteps);
634                         System.out.println(String.format("sw0.2M%.3f,%.3fl0,0r", p.x, p.y));
635                     }
636                 }
637                 System.out.println(OTSGeometryUtil.printCoordinates("#reference: \nc1,0,0\n#", referenceLine, "\n    "));
638                 System.out.println(OTSGeometryUtil.printCoordinates("#offset: \nc0,1,0\n#", offsetLine, "\n    "));
639             }
640             return false;
641         }
642         catch (OTSGeometryException exception)
643         {
644             System.err.println("Caught unexpected exception.");
645             exception.printStackTrace();
646             return false;
647         }
648     }
649 
650     /**
651      * Kink near end of design line.
652      * @throws OTSGeometryException on error
653      */
654     public static void test1() throws OTSGeometryException
655     {
656         System.out.println("Dcirc,sm-2,0a2,0,360r");
657         System.out.println("M5.0,2.5dcirc");
658         System.out.println("M4.8,2.5dcirc");
659         System.out.println("M4.6,2.7dcirc");
660         System.out.println("M2.2,2.7dcirc");
661         System.out.println("M2.2,5dcirc");
662         System.out.println("");
663         OTSLine3D referenceLine =
664                 new OTSLine3D(new OTSPoint3D(5, 2.5), new OTSPoint3D(4.8, 2.5), new OTSPoint3D(4.6, 2.7), new OTSPoint3D(2.2,
665                         2.7), new OTSPoint3D(2.2, 5));
666         System.out.println(OTSGeometryUtil.printCoordinates("#reference line: \nc1,0,0\n#", referenceLine, "\n    "));
667         // OTSLine3D.debugOffsetLine = true;
668         OTSLine3D left = referenceLine.offsetLine(2.0);
669         System.out.println(OTSGeometryUtil.printCoordinates("#left: \nc0,1,0\n#", left, "\n   "));
670         OTSLine3D right = referenceLine.offsetLine(-2.0);
671         System.out.println(OTSGeometryUtil.printCoordinates("#right: \nc0,1,0\n#", right, "\n   "));
672     }
673 
674     /**
675      * Kink halfway (far from any endpoint).
676      * @throws OTSGeometryException on error
677      */
678     public static void test2() throws OTSGeometryException
679     {
680         OTSLine3D otsLine = new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(10, 5, 0), new OTSPoint3D(20, 0, 0));
681         System.out.println(OTSGeometryUtil.printCoordinates("#reference line: \nc1,0,0\n#", otsLine, "\n    "));
682         OTSLine3D left = otsLine.offsetLine(2.0);
683         System.out.println(OTSGeometryUtil.printCoordinates("#left: \nc0,1,0\n#", left, "\n   "));
684         OTSLine3D right = otsLine.offsetLine(-2.0);
685         System.out.println(OTSGeometryUtil.printCoordinates("#buffer: \nc0,1,0\n#", right, "\n   "));
686     }
687 
688     /**
689      * Kink plus decreasing width.
690      * @throws OTSGeometryException on error
691      */
692     public static void test3() throws OTSGeometryException
693     {
694         OTSLine3D referenceLine =
695                 new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(200, 100, 0), new OTSPoint3D(1000, 0, 0));
696         System.out.println(OTSGeometryUtil.printCoordinates("#reference line: \nc1,0,0\n#", referenceLine, "\n    "));
697         OTSLine3D centerLine = referenceLine.offsetLine(-8, -5);
698         System.out.println(OTSGeometryUtil.printCoordinates("#center line: \nc0,1,0\n#", centerLine, "\n   "));
699         for (int i = 1; i < centerLine.size(); i++)
700         {
701             OTSPoint3D from = centerLine.get(i - 1);
702             OTSPoint3D to = centerLine.get(i);
703             double angle = Math.atan2(to.y - from.y, to.x - from.x);
704             System.out.println("#Direction in segment " + i + " is " + Math.toDegrees(angle));
705         }
706         OTSLine3D leftEdge = centerLine.offsetLine(1.5, 2);
707         System.out.println(OTSGeometryUtil.printCoordinates("#left edge: \nc0,0,1\n#", leftEdge, "\n   "));
708         OTSLine3D rightEdge = centerLine.offsetLine(-1.5, -2);
709         System.out.println(OTSGeometryUtil.printCoordinates("#right edge: \nc0,0,1\n#", rightEdge, "\n   "));
710     }
711 
712     /**
713      * Two kinks, (too) close together.
714      * @throws OTSGeometryException on error
715      */
716     public static void test4() throws OTSGeometryException
717     {
718         OTSLine3D reference =
719                 new OTSLine3D(new OTSPoint3D(0, 0, 0), new OTSPoint3D(20, 10, 0), new OTSPoint3D(21, 10, 0), new OTSPoint3D(22,
720                         9.5, 0), new OTSPoint3D(30, 0, 0));
721         System.out.println(OTSGeometryUtil.printCoordinates("#reference: \nc1,0,0\n#", reference, "\n    "));
722         OTSLine3D offset = reference.offsetLine(-3);
723         System.out.println(OTSGeometryUtil.printCoordinates("#offset: \nc0,1,0\n#", offset, "\n    "));
724     }
725 
726     /**
727      * Two-segment design line with minimal change of direction.
728      * @throws OTSGeometryException on error
729      */
730     public static void test5() throws OTSGeometryException
731     {
732         OTSPoint3D[] designLinePoints = new OTSPoint3D[8];
733         double radius = 10;
734         double angleStep = Math.PI / 1000;
735         double initialAngle = Math.PI / 4;
736         for (int i = 0; i < designLinePoints.length; i++)
737         {
738             double angle = initialAngle + i * angleStep;
739             designLinePoints[i] = new OTSPoint3D(radius * Math.cos(angle), radius * Math.sin(angle) - radius, 0);
740         }
741         // OTSLine3D.debugOffsetLine = true;
742         OTSLine3D reference = new OTSLine3D(designLinePoints);
743         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
744         OTSLine3D centerLine = reference.offsetLine(5);
745         System.out.println(OTSGeometryUtil.printCoordinates("#center:\nc0,1,0\n#", centerLine, "\n    "));
746         for (int i = 1; i < centerLine.size() - 1; i++)
747         {
748             // double distance =
749             // centerLine.get(i).horizontalDistanceToLineSegment(centerLine.get(0), centerLine.get(centerLine.size() - 1));
750             double distance =
751                     centerLine.get(i)
752                             .closestPointOnLine2D(new OTSLine3D(centerLine.get(0), centerLine.get(centerLine.size() - 1)))
753                             .horizontalDistanceSI(centerLine.get(i));
754             System.out.println("#distance of intermediate point " + i + " to overall line is " + distance);
755         }
756         OTSLine3D right = centerLine.offsetLine(-2);
757         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
758         OTSLine3D left = centerLine.offsetLine(2);
759         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
760     }
761 
762     /**
763      * Straight design line with some <i>noise</i> (sufficiently far from the end points).
764      * @throws OTSGeometryException on error
765      */
766     public static void test6() throws OTSGeometryException
767     {
768         System.out.println("O0,-10");
769         OTSLine3D reference =
770                 new OTSLine3D(new OTSPoint3D(10, 10, 0), new OTSPoint3D(9.999, 8, 0), new OTSPoint3D(9.996, 7.99, 0),
771                         new OTSPoint3D(9.999, 7.98, 0), new OTSPoint3D(10.03, 7.95, 0), new OTSPoint3D(10.01, 7.94, 0),
772                         new OTSPoint3D(10.0, 7.94, 0), new OTSPoint3D(10, 6, 0), new OTSPoint3D(10, 2, 0));
773         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
774         OTSLine3D right = reference.offsetLine(-2);
775         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
776         OTSLine3D left = reference.offsetLine(2);
777         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
778     }
779 
780     /**
781      * Straight design line with more <i>noise</i> (sufficiently far from the end points).
782      * @throws OTSGeometryException on error
783      */
784     public static void test7() throws OTSGeometryException
785     {
786         System.out.println("O0,-10");
787         OTSLine3D reference =
788                 new OTSLine3D(new OTSPoint3D(10, 10, 0), new OTSPoint3D(9.999, 8, 0), new OTSPoint3D(9.996, 7.99, 0),
789                         new OTSPoint3D(9.999, 7.98, 0), new OTSPoint3D(10.03, 7.95, 0), new OTSPoint3D(10.01, 7.94, 0),
790                         new OTSPoint3D(10.0, 7.94, 0), new OTSPoint3D(10, 6, 0), new OTSPoint3D(9.999, 6, 0), new OTSPoint3D(
791                                 9.996, 5.99, 0), new OTSPoint3D(9.999, 5.98, 0), new OTSPoint3D(10.03, 5.95, 0),
792                         new OTSPoint3D(10.01, 5.94, 0), new OTSPoint3D(10.0, 5.94, 0), new OTSPoint3D(10, 2, 0));
793 
794         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
795         OTSLine3D right = reference.offsetLine(-2);
796         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
797         OTSLine3D left = reference.offsetLine(2);
798         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
799     }
800 
801     /**
802      * Straight design line with more <i>noise</i> (close to the end points).
803      * @throws OTSGeometryException on error
804      */
805     public static void test8() throws OTSGeometryException
806     {
807         // System.out.println("O0,-10");
808         // OTSLine3D reference =
809         // new OTSLine3D(new OTSPoint3D(10, 9, 0), new OTSPoint3D(9.999, 8, 0), new OTSPoint3D(9.996, 7.99, 0),
810         // new OTSPoint3D(9.999, 7.98, 0), new OTSPoint3D(10.03, 7.95, 0), new OTSPoint3D(10.01, 7.94, 0),
811         // new OTSPoint3D(10.0, 7.94, 0), new OTSPoint3D(10, 6, 0), new OTSPoint3D(9.999, 6, 0), new OTSPoint3D(
812         // 9.996, 5.99, 0), new OTSPoint3D(9.999, 5.98, 0), new OTSPoint3D(10.03, 5.95, 0),
813         // new OTSPoint3D(10.01, 5.94, 0), new OTSPoint3D(10.0, 5.94, 0), new OTSPoint3D(10, 5, 0));
814         OTSLine3D reference =
815                 new OTSLine3D(new OTSPoint3D(5, -1, 0), new OTSPoint3D(5, -2, 0), new OTSPoint3D(4.9, -2.01, 0),
816                         new OTSPoint3D(5.1, -2.03, 0), new OTSPoint3D(5, -2.04, 0), new OTSPoint3D(5, -6, 0), new OTSPoint3D(
817                                 4.9, -6.01, 0), new OTSPoint3D(5.1, -6.03, 0), new OTSPoint3D(5, -6.04, 0), new OTSPoint3D(5,
818                                 -7.04, 0));
819 
820         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
821         OTSLine3D right = reference.offsetLine(-2);
822         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
823         OTSLine3D left = reference.offsetLine(2);
824         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
825 
826         reference =
827                 new OTSLine3D(new OTSPoint3D(10, 0.5, 0), new OTSPoint3D(10, -2, 0), new OTSPoint3D(9.9, -2.01, 0),
828                         new OTSPoint3D(10.1, -2.03, 0), new OTSPoint3D(10, -2.04, 0), new OTSPoint3D(10, -6, 0),
829                         new OTSPoint3D(9.9, -6.01, 0), new OTSPoint3D(10.1, -6.03, 0), new OTSPoint3D(10, -6.04, 0),
830                         new OTSPoint3D(10, -8.54, 0));
831 
832         System.out.println(OTSGeometryUtil.printCoordinates("#reference:\nc1,0,0\n#", reference, "\n    "));
833         right = reference.offsetLine(-2);
834         System.out.println(OTSGeometryUtil.printCoordinates("#right:\nc0,0,1\n#", right, "\n    "));
835         left = reference.offsetLine(2);
836         System.out.println(OTSGeometryUtil.printCoordinates("#left:\nc0,0,1\n#", left, "\n    "));
837     }
838 
839     /**
840      * Stolen from <a href="http://www.journaldev.com/1650/java-futuretask-example-program">
841      * http://www.journaldev.com/1650/java-futuretask-example-program</a>.
842      */
843     class MyCallable implements Callable<String>
844     {
845 
846         /** The reference line. */
847         private final OTSLine3D referenceLine;
848 
849         /** The offset. */
850         private final double offset;
851 
852         /** The offset method. */
853         private final OTSLine3D.OffsetMethod offsetMethod;
854 
855         /**
856          * Construct a MyCallable object.
857          * @param referenceLine OTSLine3D; the reference line
858          * @param offset double; the offset
859          * @param offsetMethod OTSLine3D.OffsetMethod; the offset method
860          */
861         MyCallable(final OTSLine3D referenceLine, final double offset, final OTSLine3D.OffsetMethod offsetMethod)
862         {
863             this.referenceLine = referenceLine;
864             this.offset = offset;
865             this.offsetMethod = offsetMethod;
866         }
867 
868         /** {@inheritDoc} */
869         @Override
870         public String call() throws Exception
871         {
872             if (checkOffsetLine(this.referenceLine, this.offset, this.offsetMethod))
873             {
874                 return "OK";
875             }
876             return "fail";
877         }
878 
879         /** {@inheritDoc} */
880         @Override
881         public final String toString()
882         {
883             return "MyCallable [referenceLine=" + this.referenceLine + ", offset=" + this.offset + ", offsetMethod="
884                     + this.offsetMethod + "]";
885         }
886 
887     }
888 
889 }