001package jmri.jmrit.display.layoutEditor; 002 003import java.util.ArrayList; 004import java.util.Arrays; 005import java.util.List; 006import jmri.BeanSetting; 007import jmri.Path; 008import jmri.Turnout; 009import org.slf4j.Logger; 010import org.slf4j.LoggerFactory; 011 012/** 013 * LayoutEditorAuxTools provides tools making use of layout connectivity 014 * available in Layout Editor panels. (More tools are in 015 * LayoutEditorTools.java.) 016 * <p> 017 * This module manages block connectivity for its associated LayoutEditor. 018 * <p> 019 * A single object of this type, obtained via {@link LayoutEditor#getLEAuxTools()} 020 * is shared across all instances of {@link ConnectivityUtil}. 021 * <p> 022 * The tools in this module are accessed via the Tools menu in Layout Editor, or 023 * directly from LayoutEditor or LayoutEditor specific modules. 024 * 025 * @author Dave Duchamp Copyright (c) 2008 026 * @author George Warner Copyright (c) 2017-2018 027 */ 028final public class LayoutEditorAuxTools { 029 // constants 030 031 // operational instance variables 032 final private LayoutModels models; 033 final private List<LayoutConnectivity> cList = new ArrayList<>(); // LayoutConnectivity list 034 private boolean blockConnectivityChanged = false; // true if block connectivity may have changed 035 private boolean initialized = false; 036 037 // constructor method 038 public LayoutEditorAuxTools(LayoutModels theModels) { 039 models = theModels; 040 } 041 042 // register a change in block connectivity that may require an update of connectivity list 043 public void setBlockConnectivityChanged() { 044 blockConnectivityChanged = true; 045 } 046 047 /** 048 * Get Connectivity involving a specific Layout Block. 049 * <p> 050 * This routine returns an ArrayList of BlockConnectivity objects involving 051 * the specified LayoutBlock. 052 * @param blk the layout block. 053 * @return the layout connectivity list, not null. 054 */ 055 public List<LayoutConnectivity> getConnectivityList(LayoutBlock blk) { 056 if (!initialized) { 057 initializeBlockConnectivity(); 058 } 059 if (blockConnectivityChanged) { 060 updateBlockConnectivity(); 061 } 062 List<LayoutConnectivity> retList = new ArrayList<>(); 063 for (LayoutConnectivity lc : cList) { 064 if ((lc.getBlock1() == blk) || (lc.getBlock2() == blk)) { 065 retList.add(lc); 066 } 067 } 068 return (retList); 069 } 070 071 /** 072 * Initializes the block connectivity (block boundaries) for a Layout Editor 073 * panel. 074 * <p> 075 * This routine sets up the LayoutConnectivity objects needed to show the 076 * current connectivity. It gets its information from arrays contained in 077 * LayoutEditor. 078 * <p> 079 * One LayoutConnectivity object is created for each block boundary -- 080 * connection points where two blocks join. Block boundaries can occur where 081 * ever a track segment in one block joins with: 1) a track segment in 082 * another block -OR- 2) a connection point in a layout turnout in another 083 * block -OR- 3) a connection point in a level crossing in another block. 084 * <p> 085 * The first block is always a track segment. The direction set in the 086 * LayoutConnectivity is the direction of the track segment alone for cases 087 * 2) and 3) above. For case 1), two track segments, the direction reflects 088 * an "average" over the two track segments. See LayoutConnectivity for the 089 * allowed values of direction. 090 * <p> 091 * Normally the initialization only occurs once after the panel is loaded. When edge 092 * connectors are used, an incomplete LayoutConnectivity table can occur due to the 093 * panel loading sequence and the complexity of edge connector relationships. 094 * An additional initialization is allowed to build the final LayoutConnectivity table. 095 */ 096 public void initializeBlockConnectivity() { 097 cList.clear(); 098 List<LayoutConnectivity> lcs = null; 099 100 for (LayoutTrackView ltv : models.getLayoutTrackViews()) { 101 if ((ltv instanceof PositionablePointView) // effectively, skip LevelXing and LayoutTurntable - why? 102 || (ltv instanceof TrackSegmentView) 103 || (ltv instanceof LayoutTurnoutView)) { // <== includes Wye. LayoutSlips, XOvers 104 lcs = ltv.getLayoutConnectivity(); 105 cList.addAll(lcs); // append to list 106 } 107 } 108 initialized = true; 109 } // initializeBlockConnectivity 110 111 /** 112 * Updates the block connectivity (block boundaries) for a Layout Editor 113 * panel after changes may have been made. 114 */ 115 private void updateBlockConnectivity() { 116 int sz = cList.size(); 117 boolean[] found = new boolean[sz]; 118 Arrays.fill(found, false); 119 120 List<LayoutConnectivity> lcs = null; 121 122 // Check for block boundaries at positionable points. 123 for (PositionablePoint p : models.getPositionablePoints()) { 124 lcs = p.getLayoutConnectivity(); 125 for (LayoutConnectivity lc : lcs) { 126 // add to list, if not already present 127 checkConnectivity(lc, found); 128 } 129 } 130 131 // Check for block boundaries at layout turnouts and level crossings 132 for (TrackSegment ts : models.getTrackSegments()) { 133 lcs = ts.getLayoutConnectivity(); 134 for (LayoutConnectivity lc : lcs) { 135 // add to list, if not already present 136 checkConnectivity(lc, found); 137 } 138 } 139 140 // check for block boundaries internal to crossover turnouts 141 for (LayoutTurnout lt : models.getLayoutTurnouts()) { 142 lcs = lt.getLayoutConnectivity(); 143 for (LayoutConnectivity lc : lcs) { 144 // add to list, if not already present 145 checkConnectivity(lc, found); 146 } 147 } 148 149 // check for block boundaries internal to slips 150 for (LayoutSlip ls : models.getLayoutSlips()) { 151 lcs = ls.getLayoutConnectivity(); 152 for (LayoutConnectivity lc : lcs) { 153 // add to list, if not already present 154 checkConnectivity(lc, found); 155 } 156 } 157 158 // delete any LayoutConnectivity objects no longer needed 159 for (int i = sz - 1; i >= 0; i--) { 160 if (!found[i]) { 161 // djd debugging - message to list connectivity being removed 162 // LayoutConnectivity xx = (LayoutConnectivity)cList.get(i); 163 // log.error(" Deleting Layout Connectivity - " + xx.getBlock1().getId() + ", " + xx.getBlock2().getId()); 164 // end debugging 165 cList.remove(i); 166 } 167 } 168 blockConnectivityChanged = false; 169 } // updateBlockConnectivity 170 171 // 172 private void checkConnectivity(LayoutConnectivity c, boolean[] found) { 173 // initialize input LayoutConnectivity components 174 LayoutBlock blk1 = c.getBlock1(); 175 LayoutBlock blk2 = c.getBlock2(); 176 177 int dir = c.getDirection(); 178 int rDir = c.getReverseDirection(); 179 180 TrackSegment track = c.getTrackSegment(); 181 LayoutTrack connected = c.getConnectedObject(); 182 HitPointType type = c.getConnectedType(); 183 184 LayoutTurnout xOver = c.getXover(); 185 int xOverType = c.getXoverBoundaryType(); 186 187 // loop over connectivity list, looking for this layout connectivity 188 for (int i = 0; i < cList.size(); i++) { 189 LayoutConnectivity lc = cList.get(i); 190 // compare input LayoutConnectivity with LayoutConnectivity from the list 191 if (xOver == null) { 192 // not a crossover block boundary 193 if ((blk1 == lc.getBlock1()) && (blk2 == lc.getBlock2()) && (track == lc.getTrackSegment()) 194 && (connected == lc.getConnectedObject()) && (type == lc.getConnectedType()) 195 && (dir == lc.getDirection())) { 196 found[i] = true; 197 break; 198 } 199 } else { 200 // boundary is in a crossover turnout 201 if ((xOver == lc.getXover()) && (xOverType == lc.getXoverBoundaryType())) { 202 if ((blk1 == lc.getBlock1()) && (blk2 == lc.getBlock2()) && (dir == lc.getDirection())) { 203 found[i] = true; 204 break; 205 } else if ((blk2 == lc.getBlock1()) && (blk1 == lc.getBlock2()) && (rDir == lc.getDirection())) { 206 found[i] = true; 207 break; 208 } 209 } 210 } 211 } 212 213 // Check to see if this connectivity is already in the list 214 // This occurs for the first layout editor panel when there 215 // are multiple panels connected by edge connectors. 216 if (cList.contains(c)) { 217 log.debug("checkConnectivity: Duplicate connection: '{}'", c); // NOI18N 218 } else { 219 cList.add(c); 220 } 221 } // checkConnectivity 222 223 /** 224 * Searches for and adds BeanSetting's to a Path as needed. 225 * <p> 226 * This method starts at the entry point to the LayoutBlock given in the 227 * Path at the block boundary specified in the LayoutConnectivity. It 228 * follows the track looking for turnout settings that are required for a 229 * train entering on this block boundary point to exit the block. If a 230 * required turnout setting is found, the turnout and its required state are 231 * used to create a BeanSetting, which is added to the Path. Such a setting 232 * can occur, for example, if a track enters a right-handed turnout from 233 * either the diverging track or the continuing track. 234 * <p> 235 * If the track branches into two tracks (for example, by entering a 236 * right-handed turnout via the throat track), the search is stopped. The 237 * search is also stopped when the track reaches a different block (or an 238 * undefined block), or reaches an end bumper. 239 * @param p path to follow until branch. 240 * @param lc layout connectivity. 241 * @param layoutBlock the layout block. 242 */ 243 public void addBeanSettings(Path p, LayoutConnectivity lc, LayoutBlock layoutBlock) { 244 p.clearSettings(); 245 LayoutTrack curConnection = null; 246 LayoutTrack prevConnection = null; 247 HitPointType typeCurConnection = HitPointType.NONE; 248 BeanSetting bs = null; 249 LayoutTurnout lt = null; 250 // process track at block boundary 251 if (lc.getBlock1() == layoutBlock) { // block1 is this LayoutBlock 252 curConnection = lc.getTrackSegment(); 253 if (curConnection != null) { // connected track in this block is a track segment 254 prevConnection = lc.getConnectedObject(); 255 typeCurConnection = HitPointType.TRACK; 256 // is this Track Segment connected to a RH, LH, or WYE turnout at the continuing or diverging track? 257 if ((lc.getConnectedType() == HitPointType.TURNOUT_B 258 || lc.getConnectedType() == HitPointType.TURNOUT_C) 259 && ((LayoutTurnout) prevConnection).getTurnoutType() != LayoutTurnout.TurnoutType.NONE 260 && LayoutTurnout.hasEnteringSingleTrack(((LayoutTurnout) prevConnection).getTurnoutType())) { 261 LayoutTurnout ltx = (LayoutTurnout) prevConnection; 262 // Track Segment connected to continuing track of turnout? 263 if (lc.getConnectedType() == HitPointType.TURNOUT_B) { 264 Turnout ltxto = ltx.getTurnout(); 265 if ( ltxto != null) { 266 bs = new BeanSetting(ltxto, ltx.getTurnoutName(), ltx.getContinuingSense()); 267 p.addSetting(bs); 268 } else { 269 log.error("No assigned turnout (A): LTO = {}, blk = {}", ltx.getName(), ltx.getLayoutBlock().getDisplayName()); // NOI18N 270 } 271 } else if (lc.getConnectedType() == HitPointType.TURNOUT_C) { 272 // is Track Segment connected to diverging track of turnout? 273 Turnout ltxto = ltx.getTurnout(); 274 if (ltxto != null) { 275 if (ltx.getContinuingSense() == Turnout.CLOSED) { 276 bs = new BeanSetting(ltxto, ltx.getTurnoutName(), Turnout.THROWN); 277 } else { 278 bs = new BeanSetting(ltxto, ltx.getTurnoutName(), Turnout.CLOSED); 279 } 280 p.addSetting(bs); 281 } else { 282 log.error("No assigned turnout (B): LTO = {}, blk = {}", ltx.getName(), ltx.getLayoutBlock().getDisplayName()); // NOI18N 283 } 284 } else { 285 log.warn("Did not decode lc.getConnectedType() of {}", lc.getConnectedType()); // NOI18N 286 } 287 } // is this Track Segment connected to the continuing track of a RH_XOVER or LH_XOVER? 288 else if (HitPointType.isTurnoutHitType(lc.getConnectedType()) 289 && ((((LayoutTurnout) prevConnection).getTurnoutType() == LayoutTurnout.TurnoutType.RH_XOVER) 290 || (((LayoutTurnout) prevConnection).getTurnoutType() == LayoutTurnout.TurnoutType.LH_XOVER))) { 291 LayoutTurnout ltz = (LayoutTurnout) prevConnection; 292 if (((ltz.getTurnoutType() == LayoutTurnout.TurnoutType.RH_XOVER) 293 && ((lc.getConnectedType() == HitPointType.TURNOUT_B) 294 || (lc.getConnectedType() == HitPointType.TURNOUT_D))) 295 || ((ltz.getTurnoutType() == LayoutTurnout.TurnoutType.LH_XOVER) 296 && ((lc.getConnectedType() == HitPointType.TURNOUT_A) 297 || (lc.getConnectedType() == HitPointType.TURNOUT_C)))) { 298 299 Turnout ltzto = ltz.getTurnout(); 300 if (ltzto != null) { 301 bs = new BeanSetting(ltzto, ltz.getTurnoutName(), Turnout.CLOSED); 302 p.addSetting(bs); 303 } else { 304 log.error("No assigned turnout (C): LTO = {}, blk = {}, TO type = {}, conn type = {}", // NOI18N 305 ltz.getName(), ltz.getLayoutBlock().getDisplayName(), ltz.getTurnoutType(), lc.getConnectedType()); 306 } 307 } 308 } // is this track section is connected to a slip? 309 else if (HitPointType.isSlipHitType(lc.getConnectedType())) { 310 LayoutSlip lsz = (LayoutSlip) prevConnection; 311 if (lsz.getSlipType() == LayoutSlip.TurnoutType.SINGLE_SLIP) { 312 if (lc.getConnectedType() == HitPointType.SLIP_C) { 313 Turnout lszto = lsz.getTurnout(); 314 if (lszto != null) { 315 bs = new BeanSetting(lszto, lsz.getTurnoutName(), lsz.getTurnoutState(LayoutTurnout.STATE_AC)); 316 p.addSetting(bs); 317 } else { 318 log.error("No assigned turnout (D): LTO = {}, blk = {}", lsz.getName(), lsz.getLayoutBlock().getDisplayName()); // NOI18N 319 } 320 Turnout lsztob = lsz.getTurnoutB(); 321 if (lsztob != null) { 322 bs = new BeanSetting(lsztob, lsz.getTurnoutBName(), lsz.getTurnoutBState(LayoutTurnout.STATE_AC)); 323 p.addSetting(bs); 324 } else { 325 log.error("No assigned turnoutB (E): LTO = {}, blk = {}", lsz.getName(), lsz.getLayoutBlock().getDisplayName()); // NOI18N 326 } 327 } else if (lc.getConnectedType() == HitPointType.SLIP_B) { 328 Turnout lszto = lsz.getTurnout(); 329 if (lszto != null) { 330 bs = new BeanSetting(lszto, lsz.getTurnoutName(), lsz.getTurnoutState(LayoutTurnout.STATE_BD)); 331 p.addSetting(bs); 332 } else { 333 log.error("No assigned turnout (F): LTO = {}, blk = {}", lsz.getName(), lsz.getLayoutBlock().getDisplayName()); // NOI18N 334 } 335 336 Turnout lsztob = lsz.getTurnoutB(); 337 if (lsztob != null) { 338 bs = new BeanSetting(lsztob, lsz.getTurnoutBName(), lsz.getTurnoutBState(LayoutTurnout.STATE_BD)); 339 p.addSetting(bs); 340 } else { 341 log.error("No assigned turnoutB (G): LTO = {}, blk = {}", lsz.getName(), lsz.getLayoutBlock().getDisplayName()); // NOI18N 342 } 343 } else if (lc.getConnectedType() == HitPointType.SLIP_A) { 344 log.debug("At connection A of a single slip which could go in two different directions"); // NOI18N 345 } else if (lc.getConnectedType() == HitPointType.SLIP_D) { 346 log.debug("At connection D of a single slip which could go in two different directions"); // NOI18N 347 } 348 } else { 349 //note: I'm adding these logs as a prequel to adding the correct code for double slips 350 if (lc.getConnectedType() == HitPointType.SLIP_A) { 351 log.debug("At connection A of a double slip which could go in two different directions"); // NOI18N 352 } else if (lc.getConnectedType() == HitPointType.SLIP_B) { 353 log.debug("At connection B of a double slip which could go in two different directions"); // NOI18N 354 } else if (lc.getConnectedType() == HitPointType.SLIP_C) { 355 log.debug("At connection C of a double slip which could go in two different directions"); // NOI18N 356 } else if (lc.getConnectedType() == HitPointType.SLIP_D) { 357 log.debug("At connection D of a double slip which could go in two different directions"); // NOI18N 358 } else { // this should NEVER happen (it should always be SLIP_A, _B, _C or _D. 359 log.info("At a double slip we could go in two different directions"); // NOI18N 360 } 361 } 362 } 363 } else { 364 // block boundary is internal to a crossover turnout 365 lt = lc.getXover(); 366 prevConnection = lt; 367 if ((lt != null) && (lt.getTurnout() != null)) { 368 int type = lc.getXoverBoundaryType(); 369 // bs is known to be null at this point 370 if (lt.getTurnout() != null) { 371 if (type == LayoutConnectivity.XOVER_BOUNDARY_AB) { 372 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 373 curConnection = lt.getConnectA(); 374 } else if (type == LayoutConnectivity.XOVER_BOUNDARY_CD) { 375 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 376 curConnection = lt.getConnectC(); 377 } else if (type == LayoutConnectivity.XOVER_BOUNDARY_AC) { 378 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.THROWN); 379 curConnection = lt.getConnectA(); 380 } else if (type == LayoutConnectivity.XOVER_BOUNDARY_BD) { 381 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.THROWN); 382 curConnection = lt.getConnectB(); 383 } else { 384 log.warn("failed to decode lc.getXoverBoundaryType() of {} (A)", lc.getXoverBoundaryType()); // NOI18N 385 } 386 } 387 typeCurConnection = HitPointType.TRACK; 388 if (bs != null) { 389 p.addSetting(bs); 390 } else { 391 log.error("No assigned turnout (H): LTO = {}, blk = {}, type = {}", lt.getName(), lt.getLayoutBlock().getDisplayName(), type); // NOI18N 392 } 393 } 394 } 395 } else if (lc.getXover() != null) { 396 // first Block is not in a Track Segment, must be block boundary internal to a crossover turnout 397 lt = lc.getXover(); 398 if ((lt != null) && (lt.getTurnout() != null)) { 399 int type = lc.getXoverBoundaryType(); 400 // bs is known to be null at this point 401 if (lt.getTurnout() != null) { 402 if (type == LayoutConnectivity.XOVER_BOUNDARY_AB) { 403 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 404 curConnection = lt.getConnectB(); 405 } else if (type == LayoutConnectivity.XOVER_BOUNDARY_CD) { 406 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 407 curConnection = lt.getConnectD(); 408 } else if (type == LayoutConnectivity.XOVER_BOUNDARY_AC) { 409 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.THROWN); 410 curConnection = lt.getConnectC(); 411 } else if (type == LayoutConnectivity.XOVER_BOUNDARY_BD) { 412 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.THROWN); 413 curConnection = lt.getConnectD(); 414 } else { 415 log.warn("failed to decode lc.getXoverBoundaryType() of {} (B)", lc.getXoverBoundaryType()); // NOI18N 416 } 417 } 418 typeCurConnection = HitPointType.TRACK; 419 if (bs != null) { 420 p.addSetting(bs); 421 } else { 422 log.error("No assigned turnout (I): LTO = {}, blk = {}, type = {}", lt.getName(), lt.getLayoutBlock().getDisplayName(), type); // NOI18N 423 } 424 } 425 } else { 426 // block2 is this LayoutBlock, and block1 is in a track segment 427 if (lc.getConnectedObject() != null) { 428 // connected object in this block is a turnout or levelxing 429 curConnection = lc.getConnectedObject(); 430 prevConnection = lc.getTrackSegment(); 431 typeCurConnection = lc.getConnectedType(); 432 if (HitPointType.isTurnoutHitType(typeCurConnection)) { 433 // connected object is a turnout 434 LayoutTurnout.TurnoutType turnoutType = ((LayoutTurnout) curConnection).getTurnoutType(); 435 if (LayoutTurnout.hasEnteringDoubleTrack(turnoutType)) { 436 // have crossover turnout 437 if ((turnoutType == LayoutTurnout.TurnoutType.DOUBLE_XOVER) 438 || ((turnoutType == LayoutTurnout.TurnoutType.RH_XOVER) && ((typeCurConnection == HitPointType.TURNOUT_A) || (typeCurConnection == HitPointType.TURNOUT_C))) 439 || ((turnoutType == LayoutTurnout.TurnoutType.LH_XOVER) && ((typeCurConnection == HitPointType.TURNOUT_B) || (typeCurConnection == HitPointType.TURNOUT_D)))) { 440 // entering turnout at a throat, cannot follow path any further 441 curConnection = null; 442 } else { 443 // entering turnout at continuing track 444 if (((LayoutTurnout) curConnection).getTurnout() != null) { 445 bs = new BeanSetting(((LayoutTurnout) curConnection).getTurnout(), ((LayoutTurnout) curConnection).getTurnoutName(), Turnout.CLOSED); 446 p.addSetting(bs); 447 } else { 448 log.error("No assigned turnout (J): LTO = {}, blk = {}", // NOI18N 449 ((LayoutTurnout) curConnection).getName(), ((LayoutTurnout) curConnection).getLayoutBlock().getDisplayName()); 450 } 451 prevConnection = curConnection; 452 if (typeCurConnection == HitPointType.TURNOUT_A) { 453 curConnection = ((LayoutTurnout) curConnection).getConnectB(); 454 } else if (typeCurConnection == HitPointType.TURNOUT_B) { 455 curConnection = ((LayoutTurnout) curConnection).getConnectA(); 456 } else if (typeCurConnection == HitPointType.TURNOUT_C) { 457 curConnection = ((LayoutTurnout) curConnection).getConnectD(); 458 } else { // typeCurConnection == LayoutEditor.HitPointTypes.TURNOUT_D per if statement 3 levels up 459 curConnection = ((LayoutTurnout) curConnection).getConnectC(); 460 } 461 typeCurConnection = HitPointType.TRACK; 462 } 463 } // must be RH, LH, or WYE turnout 464 else if (typeCurConnection == HitPointType.TURNOUT_A) { 465 // turnout throat, no bean setting needed and cannot follow Path any further 466 log.debug("At connection A of a turnout which could go in two different directions"); // NOI18N 467 curConnection = null; 468 } else if (typeCurConnection == HitPointType.TURNOUT_B) { 469 // continuing track of turnout 470 if (((LayoutTurnout) curConnection).getTurnout() != null) { 471 if (((LayoutTurnout) curConnection).getContinuingSense() == Turnout.CLOSED) { 472 bs = new BeanSetting(((LayoutTurnout) curConnection).getTurnout(), ((LayoutTurnout) curConnection).getTurnoutName(), Turnout.CLOSED); 473 } else { 474 bs = new BeanSetting(((LayoutTurnout) curConnection).getTurnout(), ((LayoutTurnout) curConnection).getTurnoutName(), Turnout.THROWN); 475 } 476 p.addSetting(bs); 477 } else { 478 log.error("No assigned turnout (K): LTO = {}, blk = {}", // NOI18N 479 ((LayoutTurnout) curConnection).getName(), ((LayoutTurnout) curConnection).getLayoutBlock().getDisplayName()); 480 } 481 prevConnection = curConnection; 482 curConnection = ((LayoutTurnout) curConnection).getConnectA(); 483 typeCurConnection = HitPointType.TRACK; 484 } else if (typeCurConnection == HitPointType.TURNOUT_C) { 485 // diverging track of turnout 486 if (((LayoutTurnout) curConnection).getTurnout() != null) { 487 if (((LayoutTurnout) curConnection).getContinuingSense() == Turnout.CLOSED) { 488 bs = new BeanSetting(((LayoutTurnout) curConnection).getTurnout(), ((LayoutTurnout) curConnection).getTurnoutName(), Turnout.THROWN); 489 } else { 490 bs = new BeanSetting(((LayoutTurnout) curConnection).getTurnout(), ((LayoutTurnout) curConnection).getTurnoutName(), Turnout.CLOSED); 491 } 492 p.addSetting(bs); 493 } else { 494 log.error("No assigned turnout (L): LTO = {}, blk = {}", // NOI18N 495 ((LayoutTurnout) curConnection).getName(), ((LayoutTurnout) curConnection).getLayoutBlock().getDisplayName()); 496 } 497 prevConnection = curConnection; 498 curConnection = ((LayoutTurnout) curConnection).getConnectA(); 499 typeCurConnection = HitPointType.TRACK; 500 } 501 } // if level crossing, skip to the connected track segment on opposite side 502 else if (typeCurConnection == HitPointType.LEVEL_XING_A) { 503 prevConnection = curConnection; 504 curConnection = ((LevelXing) curConnection).getConnectC(); 505 typeCurConnection = HitPointType.TRACK; 506 } else if (typeCurConnection == HitPointType.LEVEL_XING_C) { 507 prevConnection = curConnection; 508 curConnection = ((LevelXing) curConnection).getConnectA(); 509 typeCurConnection = HitPointType.TRACK; 510 } else if (typeCurConnection == HitPointType.LEVEL_XING_B) { 511 prevConnection = curConnection; 512 curConnection = ((LevelXing) curConnection).getConnectD(); 513 typeCurConnection = HitPointType.TRACK; 514 } else if (typeCurConnection == HitPointType.LEVEL_XING_D) { 515 prevConnection = curConnection; 516 curConnection = ((LevelXing) curConnection).getConnectB(); 517 typeCurConnection = HitPointType.TRACK; 518 } 519 } else { 520 // block boundary is internal to a crossover turnout 521 lt = lc.getXover(); 522 prevConnection = lt; 523 if ((lt != null) && (lt.getTurnout() != null)) { 524 int type = lc.getXoverBoundaryType(); 525 // bs is known to be null at this point 526 if (lt.getTurnout() != null) { 527 if (type == LayoutConnectivity.XOVER_BOUNDARY_AB) { 528 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 529 curConnection = lt.getConnectB(); 530 } else if (type == LayoutConnectivity.XOVER_BOUNDARY_CD) { 531 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 532 curConnection = lt.getConnectD(); 533 } else if (type == LayoutConnectivity.XOVER_BOUNDARY_AC) { 534 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.THROWN); 535 curConnection = lt.getConnectC(); 536 } else if (type == LayoutConnectivity.XOVER_BOUNDARY_BD) { 537 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.THROWN); 538 curConnection = lt.getConnectD(); 539 } 540 } 541 typeCurConnection = HitPointType.TRACK; 542 if (bs != null) { 543 p.addSetting(bs); 544 } else { 545 log.error("No assigned turnout (Q): LTO = {}, blk = {}", lt.getName(), lt.getLayoutBlock().getDisplayName()); // NOI18N 546 } 547 } 548 } 549 } 550 // follow path through this block - done when reaching another block, or a branching of Path 551 while (curConnection != null) { 552 if (typeCurConnection == HitPointType.TRACK) { 553 TrackSegment curTS = (TrackSegment) curConnection; 554 // track segment is current connection 555 if (curTS.getLayoutBlock() != layoutBlock) { 556 curConnection = null; 557 } else { 558 // skip over to other end of Track Segment 559 if (curTS.getConnect1() == prevConnection) { 560 prevConnection = curConnection; 561 typeCurConnection = curTS.getType2(); 562 curConnection = curTS.getConnect2(); 563 } else { 564 prevConnection = curConnection; 565 typeCurConnection = curTS.getType1(); 566 curConnection = curTS.getConnect1(); 567 } 568 // skip further if positionable point (possible anchor point) 569 if (typeCurConnection == HitPointType.POS_POINT) { 570 PositionablePoint pt = (PositionablePoint) curConnection; 571 if (pt.getType() == PositionablePoint.PointType.END_BUMPER) { 572 // reached end of track 573 curConnection = null; 574 } else { 575 // at an anchor point, find track segment on other side 576 TrackSegment track = null; 577 if (pt.getConnect1() == prevConnection) { 578 track = pt.getConnect2(); 579 } else { 580 track = pt.getConnect1(); 581 } 582 // check for block boundary 583 if ((track == null) || (track.getLayoutBlock() != layoutBlock)) { 584 // moved outside of block - anchor point was a block boundary -OR- 585 // reached the end of the defined track 586 curConnection = null; 587 } else { 588 prevConnection = curConnection; 589 curConnection = track; 590 typeCurConnection = HitPointType.TRACK; 591 } 592 } 593 } 594 } 595 } else if (HitPointType.isTurnoutHitType(typeCurConnection)) { 596 lt = (LayoutTurnout) curConnection; 597 // test for crossover turnout 598 if (lt.hasEnteringSingleTrack()) { 599 // have RH, LH, or WYE turnout 600 601 if (lt.getLayoutBlock() != layoutBlock) { 602 curConnection = null; 603 } else { 604 // turnout is in current block, test connection point 605 if (typeCurConnection == HitPointType.TURNOUT_A) { 606 // turnout throat, no bean setting needed and cannot follow possible path any further 607 curConnection = null; 608 } else if (typeCurConnection == HitPointType.TURNOUT_B) { 609 // continuing track of turnout, add a bean setting 610 if (lt.getTurnout() != null) { 611 if (lt.getContinuingSense() == Turnout.CLOSED) { 612 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 613 } else { 614 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.THROWN); 615 } 616 p.addSetting(bs); 617 } else { 618 log.error("No assigned turnout (R): LTO = {}, blk = {}", lt.getName(), lt.getLayoutBlock().getDisplayName()); // NOI18N 619 } 620 if (lt.getLayoutBlock() != layoutBlock) { 621 curConnection = null; 622 } else { 623 prevConnection = curConnection; 624 curConnection = lt.getConnectA(); 625 typeCurConnection = HitPointType.TRACK; 626 } 627 } else if (typeCurConnection == HitPointType.TURNOUT_C) { 628 // diverging track of turnout 629 if (lt.getTurnout() != null) { 630 if (lt.getContinuingSense() == Turnout.CLOSED) { 631 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.THROWN); 632 } else { 633 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 634 } 635 p.addSetting(bs); 636 } else { 637 log.error("No assigned turnout (S): LTO = {}, blk = {}", lt.getName(), lt.getLayoutBlock().getDisplayName()); // NOI18N 638 } 639 if (lt.getLayoutBlock() != layoutBlock) { 640 curConnection = null; 641 } else { 642 prevConnection = curConnection; 643 curConnection = lt.getConnectA(); 644 typeCurConnection = HitPointType.TRACK; 645 } 646 } 647 } 648 } else if (lt.getTurnoutType() == LayoutTurnout.TurnoutType.DOUBLE_XOVER) { 649 // have a double crossover turnout, cannot follow possible path any further 650 curConnection = null; 651 } else if (lt.getTurnoutType() == LayoutTurnout.TurnoutType.RH_XOVER) { 652 // have a right-handed crossover turnout 653 if ((typeCurConnection == HitPointType.TURNOUT_A) 654 || (typeCurConnection == HitPointType.TURNOUT_C)) { 655 // entry is at turnout throat, cannot follow possible path any further 656 curConnection = null; 657 } else if (typeCurConnection == HitPointType.TURNOUT_B) { 658 // entry is at continuing track of turnout 659 if (lt.getLayoutBlockB() != layoutBlock) { 660 // cross-over block different, end of current block 661 break; 662 } 663 if (lt.getTurnout() != null) { 664 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 665 p.addSetting(bs); 666 } else { 667 log.error("No assigned turnout (T): LTO = {}, blk = {}", lt.getName(), lt.getLayoutBlock().getDisplayName()); // NOI18N 668 } 669 if (lt.getLayoutBlock() != layoutBlock) { 670 // left current block 671 curConnection = null; 672 } else { 673 prevConnection = curConnection; 674 curConnection = lt.getConnectA(); 675 typeCurConnection = HitPointType.TRACK; 676 } 677 } else { // typeCurConnection == LayoutEditor.HitPointTypes.TURNOUT_D 678 // entry is at continuing track of turnout 679 if (lt.getLayoutBlockD() != layoutBlock) { 680 // cross-over block different, end of current block 681 break; 682 } 683 if (lt.getTurnout() != null) { 684 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 685 p.addSetting(bs); 686 } else { 687 log.error("No assigned turnout (U): LTO = {}, blk = {}", lt.getName(), lt.getLayoutBlock().getDisplayName()); // NOI18N 688 } 689 if (lt.getLayoutBlockC() != layoutBlock) { 690 // left current block 691 curConnection = null; 692 } else { 693 prevConnection = curConnection; 694 curConnection = lt.getConnectC(); 695 typeCurConnection = HitPointType.TRACK; 696 } 697 } 698 } else if (lt.getTurnoutType() == LayoutTurnout.TurnoutType.LH_XOVER) { 699 // have a left-handed crossover turnout 700 if ((typeCurConnection == HitPointType.TURNOUT_B) 701 || (typeCurConnection == HitPointType.TURNOUT_D)) { 702 // entry is at turnout throat, cannot follow possible path any further 703 curConnection = null; 704 } else if (typeCurConnection == HitPointType.TURNOUT_A) { 705 // entry is at continuing track of turnout 706 if (lt.getLayoutBlock() != layoutBlock) { 707 // cross-over block different, end of current block 708 break; 709 } 710 if (lt.getTurnout() != null) { 711 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 712 p.addSetting(bs); 713 } else { 714 log.error("No assigned turnout (V): LTO = {}, blk = {}", lt.getName(), lt.getLayoutBlock().getDisplayName()); // NOI18N 715 } 716 if (lt.getLayoutBlockB() != layoutBlock) { 717 // left current block 718 curConnection = null; 719 } else { 720 prevConnection = curConnection; 721 curConnection = lt.getConnectB(); 722 typeCurConnection = HitPointType.TRACK; 723 } 724 } else { // typeCurConnection == LayoutEditor.HitPointTypes.TURNOUT_C per if statement 2 levels up 725 // entry is at continuing track of turnout 726 if (lt.getLayoutBlockC() != layoutBlock) { 727 // cross-over block different, end of current block 728 break; 729 } 730 if (lt.getTurnout() != null) { 731 bs = new BeanSetting(lt.getTurnout(), lt.getTurnoutName(), Turnout.CLOSED); 732 p.addSetting(bs); 733 } else { 734 log.error("No assigned turnout (W): LTO = {}, blk = {}", lt.getName(), lt.getLayoutBlock().getDisplayName()); // NOI18N 735 } 736 if (lt.getLayoutBlockD() != layoutBlock) { 737 // left current block 738 curConnection = null; 739 } else { 740 prevConnection = curConnection; 741 curConnection = lt.getConnectD(); 742 typeCurConnection = HitPointType.TRACK; 743 } 744 } 745 } 746 } else if (typeCurConnection == HitPointType.LEVEL_XING_A) { 747 // have a level crossing connected at A 748 if (((LevelXing) curConnection).getLayoutBlockAC() != layoutBlock) { 749 // moved outside of this block 750 curConnection = null; 751 } else { 752 // move to other end of this section of this level crossing track 753 prevConnection = curConnection; 754 curConnection = ((LevelXing) curConnection).getConnectC(); 755 typeCurConnection = HitPointType.TRACK; 756 } 757 } else if (typeCurConnection == HitPointType.LEVEL_XING_B) { 758 // have a level crossing connected at B 759 if (((LevelXing) curConnection).getLayoutBlockBD() != layoutBlock) { 760 // moved outside of this block 761 curConnection = null; 762 } else { 763 // move to other end of this section of this level crossing track 764 prevConnection = curConnection; 765 curConnection = ((LevelXing) curConnection).getConnectD(); 766 typeCurConnection = HitPointType.TRACK; 767 } 768 } else if (typeCurConnection == HitPointType.LEVEL_XING_C) { 769 // have a level crossing connected at C 770 if (((LevelXing) curConnection).getLayoutBlockAC() != layoutBlock) { 771 // moved outside of this block 772 curConnection = null; 773 } else { 774 // move to other end of this section of this level crossing track 775 prevConnection = curConnection; 776 curConnection = ((LevelXing) curConnection).getConnectA(); 777 typeCurConnection = HitPointType.TRACK; 778 } 779 } else if (typeCurConnection == HitPointType.LEVEL_XING_D) { 780 // have a level crossing connected at D 781 if (((LevelXing) curConnection).getLayoutBlockBD() != layoutBlock) { 782 // moved outside of this block 783 curConnection = null; 784 } else { 785 // move to other end of this section of this level crossing track 786 prevConnection = curConnection; 787 curConnection = ((LevelXing) curConnection).getConnectB(); 788 typeCurConnection = HitPointType.TRACK; 789 } 790 } else if (HitPointType.isSlipHitType(typeCurConnection)) { 791 LayoutSlip ls = (LayoutSlip) curConnection; 792 if (ls.getLayoutBlock() != layoutBlock) { 793 curConnection = null; 794 } else if (ls.getSlipType() == LayoutSlip.TurnoutType.SINGLE_SLIP) { 795 if (typeCurConnection == HitPointType.SLIP_C) { 796 if (ls.getTurnout() != null) { 797 bs = new BeanSetting(ls.getTurnout(), ls.getTurnoutName(), ls.getTurnoutState(LayoutTurnout.STATE_AC)); 798 p.addSetting(bs); 799 } else { 800 log.error("No assigned turnout (X): LTO = {}, blk = {}", ls.getName(), ls.getLayoutBlock().getDisplayName()); // NOI18N 801 } 802 if (ls.getTurnoutB() != null) { 803 bs = new BeanSetting(ls.getTurnoutB(), ls.getTurnoutBName(), ls.getTurnoutBState(LayoutTurnout.STATE_AC)); 804 p.addSetting(bs); 805 } else { 806 log.error("No assigned turnoutB (Y): LTO = {}, blk = {}", ls.getName(), ls.getLayoutBlock().getDisplayName()); // NOI18N 807 } 808 prevConnection = curConnection; 809 curConnection = ((LayoutSlip) curConnection).getConnectC(); 810 typeCurConnection = HitPointType.TRACK; 811 } else if (typeCurConnection == HitPointType.SLIP_B) { 812 if (ls.getTurnout() != null) { 813 bs = new BeanSetting(ls.getTurnout(), ls.getTurnoutName(), ls.getTurnoutState(LayoutTurnout.STATE_BD)); 814 p.addSetting(bs); 815 } else { 816 log.error("No assigned turnout (Z): LTO = {}, blk = {}", ls.getName(), ls.getLayoutBlock().getDisplayName()); // NOI18N 817 } 818 819 if (ls.getTurnoutB() != null) { 820 bs = new BeanSetting(ls.getTurnoutB(), ls.getTurnoutBName(), ls.getTurnoutBState(LayoutTurnout.STATE_BD)); 821 p.addSetting(bs); 822 } else { 823 log.error("No assigned turnoutB (1): LTO = {}, blk = {}", ls.getName(), ls.getLayoutBlock().getDisplayName()); // NOI18N 824 } 825 prevConnection = curConnection; 826 curConnection = ((LayoutSlip) curConnection).getConnectB(); 827 typeCurConnection = HitPointType.TRACK; 828 } else { 829 //Else could be going in the slip direction 830 curConnection = null; 831 } 832 833 } else { 834 //At double slip, can not follow any further 835 curConnection = null; 836 } 837 } else if (HitPointType.isTurntableRayHitType(typeCurConnection)) { 838 if (log.isDebugEnabled()) { 839 log.debug("Layout Block: {}, found track type: {}, to " // NOI18N 840 + "Block: {}, is potentially assigned to turntable ray", // NOI18N 841 layoutBlock.getDisplayName(), 842 typeCurConnection, 843 p.getBlock().getDisplayName() 844 ); 845 } 846 curConnection = null; 847 } else { 848 // catch when some new type got added 849 log.error("Layout Block: {} found unknown track type: {}" // NOI18N 850 + " to Block: {}", 851 layoutBlock.getDisplayName(), 852 typeCurConnection, 853 p.getBlock().getDisplayName() 854 ); 855 break; 856 } 857 } 858 } // addBeanSettings 859 860 // initialize logging 861 private final static Logger log 862 = LoggerFactory.getLogger(LayoutEditorAuxTools.class); 863}