001package jmri.jmrit.display.layoutEditor;
002
003/**
004 * Enum denoting the different behaviors of different
005 * types of "HitPoints".
006 * <p>
007 * Extracted from static in constants in LayoutEditor
008 *
009 * @author Dave Duchamp Copyright: (c) 2004-2007
010 * @author George Warner Copyright: (c) 2017-2019
011 * @author Bob Jacobsen Copyright: (c) 2020
012 */
013
014public enum HitPointType {
015                    //  Historical numerical values, used in old files, now ordinals with tests
016    NONE,           //     0
017    POS_POINT,      //     1
018    TURNOUT_A,      //     2    throat for RH, LH, and WYE turnouts
019    TURNOUT_B,      //     3    continuing route for RH and LH turnouts
020    TURNOUT_C,      //     4    diverging route for RH and LH turnouts
021    TURNOUT_D,      //     5    4th route for crossovers
022    LEVEL_XING_A,   //     6
023    LEVEL_XING_B,   //     7
024    LEVEL_XING_C,   //     8
025    LEVEL_XING_D,   //     9
026    TRACK,          //     10
027    TURNOUT_CENTER,   //     11    non-connection points should be last
028    LEVEL_XING_CENTER,  //     12
029    TURNTABLE_CENTER,   //     13
030    LAYOUT_POS_LABEL,   //     14
031    LAYOUT_POS_JCOMP,   //     15
032    MULTI_SENSOR,   //     16
033    MARKER,         //     17
034    TRACK_CIRCLE_CENTRE,   //     18
035    UNUSED_19,      //     19
036    SLIP_CENTER,    //     20   TODO: should be deprecated (use SLIP_LEFT & SLIP_RIGHT instead)
037    SLIP_A,         //     21
038    SLIP_B,         //     22
039    SLIP_C,         //     23
040    SLIP_D,         //     24
041    SLIP_LEFT,      //     25
042    SLIP_RIGHT,     //     26
043    UNUSED_27,      //     27
044    UNUSED_28,                //     28
045    UNUSED_29,                //     29
046    BEZIER_CONTROL_POINT_0,   //     30    offset for TrackSegment Bezier control points , minimum)
047    BEZIER_CONTROL_POINT_1,   //     31     \
048    BEZIER_CONTROL_POINT_2,   //     32      \
049    BEZIER_CONTROL_POINT_3,   //     33       \
050    BEZIER_CONTROL_POINT_4,   //     34        } -- DON'T USE THESE; PLACEHOLDERS ONLY
051    BEZIER_CONTROL_POINT_5,   //     35       /
052    BEZIER_CONTROL_POINT_6,   //     36      /
053    BEZIER_CONTROL_POINT_7,   //     37     /
054    BEZIER_CONTROL_POINT_8,   //     38    offset for TrackSegment Bezier control points , maximum)
055    SHAPE_CENTER,    //     39
056    SHAPE_POINT_0,   //     40    offset for Shape points, minimum)
057    SHAPE_POINT_1,   //     41     \
058    SHAPE_POINT_2,   //     42      \
059    SHAPE_POINT_3,   //     43       \
060    SHAPE_POINT_4,   //     44        \ __ DON'T USE THESE; PLACEHOLDERS ONLY
061    SHAPE_POINT_5,   //     45        /
062    SHAPE_POINT_6,   //     46       /
063    SHAPE_POINT_7,   //     47      /
064    SHAPE_POINT_8,   //     48     /
065    SHAPE_POINT_9,   //     49    offset for Shape points ,   //     maximum)
066    TURNTABLE_RAY_0,   //     50    offset for turntable connection points ,   //     minimum)
067    TURNTABLE_RAY_1,   //     51    \
068    TURNTABLE_RAY_2,   //     52     \
069    TURNTABLE_RAY_3,   //     53      \
070    TURNTABLE_RAY_4,   //     54       \
071    TURNTABLE_RAY_5,   //     55        \
072    TURNTABLE_RAY_6,   //     56         \
073    TURNTABLE_RAY_7,   //     57          |
074    TURNTABLE_RAY_8,   //     58          |
075    TURNTABLE_RAY_9,   //     59          |
076    TURNTABLE_RAY_10,   //     60         |
077    TURNTABLE_RAY_11,   //     61         |
078    TURNTABLE_RAY_12,   //     62         |
079    TURNTABLE_RAY_13,   //     63         |
080    TURNTABLE_RAY_14,   //     64         |
081    TURNTABLE_RAY_15,   //     65         |
082    TURNTABLE_RAY_16,   //     66         |
083    TURNTABLE_RAY_17,   //     67         |
084    TURNTABLE_RAY_18,   //     68         |
085    TURNTABLE_RAY_19,   //     69         |
086    TURNTABLE_RAY_20,   //     70         |
087    TURNTABLE_RAY_21,   //     71         |
088    TURNTABLE_RAY_22,   //     72         |
089    TURNTABLE_RAY_23,   //     73         |
090    TURNTABLE_RAY_24,   //     74         |
091    TURNTABLE_RAY_25,   //     75         |
092    TURNTABLE_RAY_26,   //     76         |
093    TURNTABLE_RAY_27,   //     77         |
094    TURNTABLE_RAY_28,   //     78         |
095    TURNTABLE_RAY_29,   //     79         |
096    TURNTABLE_RAY_30,   //     80         |
097    TURNTABLE_RAY_31,   //     81         |
098    TURNTABLE_RAY_32,   //     82         |
099    TURNTABLE_RAY_33,   //     83         |
100    TURNTABLE_RAY_34,   //     84         |
101    TURNTABLE_RAY_35,   //     85         |
102    TURNTABLE_RAY_36,   //     86         |
103    TURNTABLE_RAY_37,   //     87         |
104    TURNTABLE_RAY_38,   //     88         |
105    TURNTABLE_RAY_39,   //     89         |
106    TURNTABLE_RAY_40,   //     90         |
107    TURNTABLE_RAY_41,   //     91         |
108    TURNTABLE_RAY_42,   //     92         |
109    TURNTABLE_RAY_43,   //     93         |
110    TURNTABLE_RAY_44,   //     94         |
111    TURNTABLE_RAY_45,   //     95         | -- DON'T USE THESE; PLACEHOLDERS ONLY
112    TURNTABLE_RAY_46,   //     96         |
113    TURNTABLE_RAY_47,   //     97         |
114    TURNTABLE_RAY_48,   //     98         |
115    TURNTABLE_RAY_49,   //     99         |
116    TURNTABLE_RAY_50,   //     100         |
117    TURNTABLE_RAY_51,   //     101         |
118    TURNTABLE_RAY_52,   //     102         |
119    TURNTABLE_RAY_53,   //     103         |
120    TURNTABLE_RAY_54,   //     104         |
121    TURNTABLE_RAY_55,   //     105         |
122    TURNTABLE_RAY_56,   //     106         |
123    TURNTABLE_RAY_57,   //     107         |
124    TURNTABLE_RAY_58,   //     108        /
125    TURNTABLE_RAY_59,   //     109       /
126    TURNTABLE_RAY_60,   //     110      /
127    TURNTABLE_RAY_61,   //     111     /
128    TURNTABLE_RAY_62,   //     112    /
129    TURNTABLE_RAY_63,   //     113
130    BLOCKCONTENTSICON;
131
132    /**
133     * @param hitType the hit point type
134     * @return true if this is for a connection to a LayoutTrack
135     */
136    protected static boolean isConnectionHitType(HitPointType hitType) {
137        switch (hitType) {
138            case POS_POINT:
139            case TURNOUT_A:
140            case TURNOUT_B:
141            case TURNOUT_C:
142            case TURNOUT_D:
143            case LEVEL_XING_A:
144            case LEVEL_XING_B:
145            case LEVEL_XING_C:
146            case LEVEL_XING_D:
147            case TRACK:
148            case SLIP_A:
149            case SLIP_B:
150            case SLIP_C:
151            case SLIP_D:
152                return true; // these are all connection types
153            case NONE:
154            case TURNOUT_CENTER:
155            case LEVEL_XING_CENTER:
156            case TURNTABLE_CENTER:
157            case LAYOUT_POS_LABEL:
158            case LAYOUT_POS_JCOMP:
159            case MULTI_SENSOR:
160            case MARKER:
161            case TRACK_CIRCLE_CENTRE:
162            case SLIP_CENTER:
163            case SLIP_LEFT:
164            case SLIP_RIGHT:
165                return false; // these are not
166            default:
167                break;
168        }
169        if (isBezierHitType(hitType)) {
170            return false; // these are not
171        } else if (isTurntableRayHitType(hitType)) {
172            return true; // these are all connection types
173        }
174        return false; // This is unexpected
175    }
176
177    /**
178     * @param hitType the hit point type
179     * @return true if this hit type is for a layout control
180     */
181    protected static boolean isControlHitType(HitPointType hitType) {
182        switch (hitType) {
183            case TURNOUT_CENTER:
184            case SLIP_CENTER:
185            case SLIP_LEFT:
186            case SLIP_RIGHT:
187                return true; // these are all control types
188            case POS_POINT:
189            case TURNOUT_A:
190            case TURNOUT_B:
191            case TURNOUT_C:
192            case TURNOUT_D:
193            case LEVEL_XING_A:
194            case LEVEL_XING_B:
195            case LEVEL_XING_C:
196            case LEVEL_XING_D:
197            case TRACK:
198            case SLIP_A:
199            case SLIP_B:
200            case SLIP_C:
201            case SLIP_D:
202            case NONE:
203            case LEVEL_XING_CENTER:
204            case TURNTABLE_CENTER:
205            case LAYOUT_POS_LABEL:
206            case LAYOUT_POS_JCOMP:
207            case MULTI_SENSOR:
208            case MARKER:
209            case TRACK_CIRCLE_CENTRE:
210                return false; // these are not
211            default:
212                break;
213        }
214        if (isBezierHitType(hitType)) {
215            return false; // these are not control types
216        } else if (isTurntableRayHitType(hitType)) {
217            return true; // these are all control types
218        }
219        return false; // This is unexpected
220    }
221
222    protected static boolean isTurnoutHitType(HitPointType hitType) {
223        return (hitType.compareTo(HitPointType.TURNOUT_A) >= 0) && (hitType.compareTo(HitPointType.TURNOUT_D) <= 0);
224    }
225
226    protected static boolean isSlipHitType(HitPointType hitType) {
227        return (hitType.compareTo(HitPointType.SLIP_A) >= 0) && (hitType.compareTo(HitPointType.SLIP_RIGHT) <= 0);
228    }
229
230    protected static boolean isBezierHitType(HitPointType hitType) {
231        return (hitType.compareTo(HitPointType.BEZIER_CONTROL_POINT_0) >= 0) && (hitType.compareTo(HitPointType.BEZIER_CONTROL_POINT_8) <= 0);
232    }
233
234    protected static boolean isLevelXingHitType(HitPointType hitType) {
235        return (hitType.compareTo(HitPointType.LEVEL_XING_A) >= 0) && (hitType.compareTo(HitPointType.LEVEL_XING_D) <= 0);
236    }
237
238    protected static boolean isTurntableRayHitType(HitPointType hitType) {
239        return (hitType.compareTo(HitPointType.TURNTABLE_RAY_0) >= 0) && (hitType.compareTo(HitPointType.TURNTABLE_RAY_63) <= 0);
240    }
241
242    /**
243     * @param hitType the hit point type
244     * @return true if this is for a popup menu
245     */
246    protected static boolean isPopupHitType(HitPointType hitType) {
247        switch (hitType) {
248            case LEVEL_XING_CENTER:
249            case POS_POINT:
250            case SLIP_CENTER:
251            case SLIP_LEFT:
252            case SLIP_RIGHT:
253            case TRACK:
254            case TRACK_CIRCLE_CENTRE:
255            case TURNOUT_CENTER:
256            case TURNTABLE_CENTER:
257                return true;
258            case LAYOUT_POS_JCOMP:
259            case LAYOUT_POS_LABEL:
260            case LEVEL_XING_A:
261            case LEVEL_XING_B:
262            case LEVEL_XING_C:
263            case LEVEL_XING_D:
264            case MARKER:
265            case MULTI_SENSOR:
266            case NONE:
267            case SLIP_A:
268            case SLIP_B:
269            case SLIP_C:
270            case SLIP_D:
271            case TURNOUT_A:
272            case TURNOUT_B:
273            case TURNOUT_C:
274            case TURNOUT_D:
275                return false; // these are not
276            default:
277                break;
278        }
279        if (isBezierHitType(hitType)) {
280            return true; // these are all popup hit types
281        } else if (isTurntableRayHitType(hitType)) {
282            return true; // these are all popup hit types
283        }
284        return false;
285    }
286
287    // *****************************************************************
288    //    TURNTABLE_RAY support
289    // *****************************************************************
290    /**
291     * Find the 0-63 index with respect to TURNTABLE_RAY_0
292     * of a given enum entry.  Throws {@link IllegalArgumentException} if
293     * the given enum value isn't one of the TURNTABLE_RAY_n entries.
294     * <p>
295     * Ideally, this would be replaced by turntable code that works
296     * directly with the enum values as a step toward using objects
297     * to implement hit points.
298     * @return (Temporary) 0-63 index of the enum element
299     */
300    protected int turntableTrackIndex() {
301        int result = this.ordinal() - HitPointType.TURNTABLE_RAY_0.ordinal();
302        if (result < 0) {
303            throw new IllegalArgumentException(this.toString() + " is not a valid TURNTABLE_RAY");
304        }
305        if (result > 63) {
306            throw new IllegalArgumentException(this.toString() + " is not a valid TURNTABLE_RAY");
307        }
308        return result;
309    }
310
311    /**
312     * Return a specific TURNTABLE_RAY from its 0-63 index.
313     * Throws {@link IllegalArgumentException} if
314     * the given index value isn't valid for the TURNTABLE_RAY entries.
315     * <p>
316     * Ideally, this would be replaced by turntable code that works
317     * directly with the enum values as a step toward using objects
318     * to implement hit points.
319     * @param i (Temporary) 0-63 index of the enum element
320     * @return Requested enum element
321     */
322    protected static HitPointType turntableTrackIndexedValue(int i) {
323        if (i < 0 || i > 63) {
324            throw new IllegalArgumentException(i + " is not a valid TURNTABLE_RAY index");
325        }
326        return HitPointType.values()[(TURNTABLE_RAY_0.ordinal() + i)];
327    }
328
329    /**
330     * Return an array of the valid TURNTABLE_RAY enum values.
331     * Meant for interations over the set of rays.  Order is
332     * from 0 to 63.
333     * @return (Temporary) Array containing TURNTABLE_RAY_0 through TURNTABLE_RAY_63
334     */
335    protected static HitPointType[] turntableValues() {
336        return new HitPointType[]{TURNTABLE_RAY_0, TURNTABLE_RAY_1, TURNTABLE_RAY_2, TURNTABLE_RAY_3, TURNTABLE_RAY_4, TURNTABLE_RAY_5, TURNTABLE_RAY_6, TURNTABLE_RAY_7, TURNTABLE_RAY_8, TURNTABLE_RAY_9, TURNTABLE_RAY_10, TURNTABLE_RAY_11, TURNTABLE_RAY_12, TURNTABLE_RAY_13, TURNTABLE_RAY_14, TURNTABLE_RAY_15, TURNTABLE_RAY_16, TURNTABLE_RAY_17, TURNTABLE_RAY_18, TURNTABLE_RAY_19, TURNTABLE_RAY_20, TURNTABLE_RAY_21, TURNTABLE_RAY_22, TURNTABLE_RAY_23, TURNTABLE_RAY_24, TURNTABLE_RAY_25, TURNTABLE_RAY_26, TURNTABLE_RAY_27, TURNTABLE_RAY_28, TURNTABLE_RAY_29, TURNTABLE_RAY_30, TURNTABLE_RAY_31, TURNTABLE_RAY_32, TURNTABLE_RAY_33, TURNTABLE_RAY_34, TURNTABLE_RAY_35, TURNTABLE_RAY_36, TURNTABLE_RAY_37, TURNTABLE_RAY_38, TURNTABLE_RAY_39, TURNTABLE_RAY_40, TURNTABLE_RAY_41, TURNTABLE_RAY_42, TURNTABLE_RAY_43, TURNTABLE_RAY_44, TURNTABLE_RAY_45, TURNTABLE_RAY_46, TURNTABLE_RAY_47, TURNTABLE_RAY_48, TURNTABLE_RAY_49, TURNTABLE_RAY_50, TURNTABLE_RAY_51, TURNTABLE_RAY_52, TURNTABLE_RAY_53, TURNTABLE_RAY_54, TURNTABLE_RAY_55, TURNTABLE_RAY_56, TURNTABLE_RAY_57, TURNTABLE_RAY_58, TURNTABLE_RAY_59, TURNTABLE_RAY_60, TURNTABLE_RAY_61, TURNTABLE_RAY_62, TURNTABLE_RAY_63};
337    }
338
339    // *****************************************************************
340    //    SHAPE_POINT support
341    // *****************************************************************
342    /**
343     * Find the 0-9 index with respect to SHAPE_POINT_0
344     * of a given enum entry.  Throws {@link IllegalArgumentException} if
345     * the given enum value isn't one of the SHAPE_POINT_n entries.
346     * <p>
347     * Ideally, this would be replaced by shape code that works
348     * directly with the enum values as a step toward using objects
349     * to implement hit points.
350     * @return (Temporary) 0-9 index of the enum element
351     */
352    protected int shapePointIndex() {
353        int result = this.ordinal() - HitPointType.SHAPE_POINT_0.ordinal();
354        if (result < 0) {
355            throw new IllegalArgumentException(this.toString() + " is not a valid SHAPE_POINT");
356        }
357        if (result > 9) {
358            throw new IllegalArgumentException(this.toString() + " is not a valid SHAPE_POINT");
359        }
360        return result;
361    }
362
363    /**
364     * Return a specific SHAPE_POINT from its 0-9 index.
365     * Throws {@link IllegalArgumentException} if
366     * the given index value isn't valid for the SHAPE_POINT entries.
367     * <p>
368     * Ideally, this would be replaced by shape code that works
369     * directly with the enum values as a step toward using objects
370     * to implement hit points.
371     * @param i (Temporary) 0-9 index of the enum element
372     * @return Requested enum element
373     */
374    protected static HitPointType shapePointIndexedValue(int i) {
375        if (i < 0 || i > 9) {
376            throw new IllegalArgumentException(i + " is not a valid SHAPE_POINT index");
377        }
378        return HitPointType.values()[(SHAPE_POINT_0.ordinal() + i)];
379    }
380
381    /**
382     * Return an array of the valid SHAPE_POINT enum values.
383     * Meant for interations over the set of points.  Order is
384     * from 0 to 9.
385     * @return (Temporary) Array containing SHAPE_POINT_0 through SHAPE_POINT_9
386     */
387    protected static HitPointType[] shapePointValues() {
388        return new HitPointType[]{SHAPE_POINT_0, SHAPE_POINT_1, SHAPE_POINT_2, SHAPE_POINT_3, SHAPE_POINT_4, SHAPE_POINT_5, SHAPE_POINT_6, SHAPE_POINT_7, SHAPE_POINT_8, SHAPE_POINT_9};
389    }
390
391    protected static boolean isShapePointOffsetHitPointType(HitPointType t) {
392        return (t.compareTo(SHAPE_POINT_0) >= 0) && (t.compareTo(SHAPE_POINT_9) <= 0);
393    }
394    // limited use, remove?
395    public static final int NUM_SHAPE_POINTS = 10;
396
397    // *****************************************************************
398    //    BEZIER_CONTROL_POINT support
399    // *****************************************************************
400    /**
401     * Find the 0-8 index with respect to BEZIER_CONTROL_POINT_0
402     * of this enum entry. Throws {@link IllegalArgumentException} if
403     * the enum value isn't one of the BEZIER_CONTROL_POINT_n entries.
404     * <p>
405     * Ideally, this would be replaced by bezier code that works
406     * directly with the enum values as a step toward using objects
407     * to implement hit points.
408     * @return (Temporary) 0-8 index of this enum
409     */
410    protected int bezierPointIndex() {
411        int result = this.ordinal() - HitPointType.BEZIER_CONTROL_POINT_0.ordinal();
412        if (result < 0) {
413            throw new IllegalArgumentException(this.toString() + " is not a valid BEZIER_CONTROL_POINT");
414        }
415        if (result > 8) {
416            throw new IllegalArgumentException(this.toString() + " is not a valid BEZIER_CONTROL_POINT");
417        }
418        return result;
419    }
420
421    /**
422     * Return a specific BEZIER_CONTROL_POINT from its 0-8 index.
423     * Throws {@link IllegalArgumentException} if
424     * the given index value isn't valid for the SHAPE_POINT entries.
425     * <p>
426     * Ideally, this would be replaced by shape code that works
427     * directly with the enum values as a step toward using objects
428     * to implement hit points.
429     * @param i (Temporary) 0-8 index of the enum element
430     * @return Requested enum element
431     */
432    protected static HitPointType bezierPointIndexedValue(int i) {
433        if (i < 0 || i > 8) {
434            throw new IllegalArgumentException(i + " is not a valid BEZIER_CONTROL_POINT index");
435        }
436        return HitPointType.values()[(BEZIER_CONTROL_POINT_0.ordinal() + i)];
437    }
438    // limited use, remove?
439    public static final int NUM_BEZIER_CONTROL_POINTS = 9;
440
441}