001package jmri; 002 003import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; 004 005import java.beans.*; 006import java.util.ArrayList; 007import java.util.List; 008 009import javax.annotation.CheckForNull; 010import javax.annotation.Nonnull; 011 012import jmri.jmrit.display.layoutEditor.LayoutEditor; 013 014/** 015 * Sections represent a group of one or more connected Blocks that may be 016 * allocated to a train traveling in a given direction. 017 * <p> 018 * A Block may be in multiple Sections. All Blocks contained in a given section 019 * must be unique. Blocks are kept in order--the first block is connected to the 020 * second, the second is connected to the third, etc. 021 * <p> 022 * A Block in a Section must be connected to the Block before it (if there is 023 * one) and to the Block after it (if there is one), but may not be connected to 024 * any other Block in the Section. This restriction is enforced when a Section 025 * is created, and checked when a Section is loaded from disk. 026 * <p> 027 * A Section has a "direction" defined by the sequence in which Blocks are added 028 * to the Section. A train may run through a Section in either the forward 029 * direction (from first block to last block) or reverse direction (from last 030 * block to first block). 031 * <p> 032 * A Section has one or more EntryPoints. Each EntryPoint is a Path of one of 033 * the Blocks in the Section that defines a connection to a Block outside of the 034 * Section. EntryPoints are grouped into two lists: "forwardEntryPoints" - entry 035 * through which will result in a train traveling in the "forward" direction 036 * "reverseEntryPoints" - entry through which will result in a train traveling 037 * in the "reverse" direction Note that "forwardEntryPoints" are also reverse 038 * exit points, and vice versa. 039 * <p> 040 * A Section has one of the following states" FREE - available for allocation by 041 * a dispatcher FORWARD - allocated for travel in the forward direction REVERSE 042 * - allocated for travel in the reverse direction 043 * <p> 044 * A Section has an occupancy. A Section is OCCUPIED if any of its Blocks is 045 * OCCUPIED. A Section is UNOCCUPIED if all of its Blocks are UNOCCUPIED 046 * <p> 047 * A Section of may be allocated to only one train at a time, even if the trains 048 * are travelling in the same direction. If a Section has sufficient space for 049 * multiple trains travelling in the same direction it should be broken up into 050 * multiple Sections so the trains can follow each other through the original 051 * Section. 052 * <p> 053 * A Section may not contain any reverse loops. The track that is reversed in a 054 * reverse loop must be in a separate Section. 055 * <p> 056 * Each Section optionally carries two direction sensors, one for the forward 057 * direction and one for the reverse direction. These sensors force signals for 058 * travel in their respective directions to "RED" when they are active. When the 059 * Section is free, both the sensors are Active. These internal sensors follow 060 * the state of the Section, permitting signals to function normally in the 061 * direction of allocation. 062 * <p> 063 * Each Section optionally carries two stopping sensors, one for the forward 064 * direction and one for the reverse direction. These sensors change to active 065 * when a train traversing the Section triggers its sensing device. Stopping 066 * sensors are physical layout sensors, and may be either point sensors or 067 * occupancy sensors for short blocks at the end of the Section. A stopping 068 * sensor is used during automatic running to stop a train that has reached the 069 * end of its allocated Section. This is needed, for example, to allow a train 070 * to enter a passing siding and clear the track behind it. When not running 071 * automatically, these sensors may be used to light panel lights to notify the 072 * dispatcher that the train has reached the end of the Section. 073 * <p> 074 * This Section implementation provides for delayed initialization of blocks and 075 * direction sensors to be independent of order of items in panel files. 076 * 077 * @author Dave Duchamp Copyright (C) 2008,2010 078 * @author Bob Jacobsen Copyright (C) 2022 079 */ 080public interface Section extends NamedBean { 081 082 /** 083 * The value of {@link #getState()} if section is available for allocation. 084 */ 085 public static final int FREE = 0x02; 086 087 /** 088 * The value of {@link #getState()} if section is allocated for travel in 089 * the forward direction. 090 */ 091 public static final int FORWARD = 0x04; 092 093 /** 094 * The value of {@link #getState()} if section is allocated for travel in 095 * the reverse direction. 096 */ 097 public static final int REVERSE = 0X08; 098 099 /** 100 * Value representing an occupied section. 101 */ 102 public static final int OCCUPIED = Block.OCCUPIED; 103 104 /** 105 * Value representing an unoccupied section. 106 */ 107 public static final int UNOCCUPIED = Block.UNOCCUPIED; 108 109 /** 110 * Provide generic access to internal state. 111 * <p> 112 * This generally shouldn't be used by Java code; use the class-specific 113 * form instead (e.g. setCommandedState in Turnout). This is provided to 114 * make scripts access easier to read. 115 * <p> 116 * This isn't an exact override because it doesn't throw JmriException 117 * 118 * @param newState the state 119 */ 120 @Override 121 public void setState(int newState); 122 123 /** 124 * Get the occupancy of a Section. 125 * 126 * @return {@link #OCCUPIED}, {@link #UNOCCUPIED}, or the state of the first 127 * block that is neither occupied or unoccupied 128 */ 129 public int getOccupancy(); 130 131 public String getForwardBlockingSensorName(); 132 133 public Sensor getForwardBlockingSensor(); 134 135 public Sensor setForwardBlockingSensorName(String forwardSensor); 136 137 public void delayedSetForwardBlockingSensorName(String forwardSensor); 138 139 public String getReverseBlockingSensorName(); 140 141 public Sensor setReverseBlockingSensorName(String reverseSensor); 142 143 public void delayedSetReverseBlockingSensorName(String reverseSensor); 144 145 public Sensor getReverseBlockingSensor(); 146 147 public Block getLastBlock(); 148 149 public String getForwardStoppingSensorName(); 150 151 @CheckForNull 152 public Sensor getForwardStoppingSensor(); 153 154 public Sensor setForwardStoppingSensorName(String forwardSensor); 155 156 public void delayedSetForwardStoppingSensorName(String forwardSensor); 157 158 public String getReverseStoppingSensorName(); 159 160 @CheckForNull 161 public Sensor setReverseStoppingSensorName(String reverseSensor); 162 163 public void delayedSetReverseStoppingSensorName(String reverseSensor); 164 165 @CheckForNull 166 public Sensor getReverseStoppingSensor(); 167 168 /** 169 * Add a Block to the Section. Block and sequence number must be unique 170 * within the Section. Block sequence numbers are set automatically as 171 * blocks are added. 172 * 173 * @param b the block to add 174 * @return true if Block was added or false if Block does not connect to the 175 * current Block, or the Block is not unique. 176 */ 177 public boolean addBlock(Block b); 178 179 public void delayedAddBlock(String blockName); 180 181 /** 182 * Get a list of blocks in this section 183 * 184 * @return a list of blocks 185 */ 186 @Nonnull 187 public List<Block> getBlockList(); 188 189 /** 190 * Gets the number of Blocks in this Section 191 * 192 * @return the number of blocks 193 */ 194 public int getNumBlocks(); 195 196 /** 197 * Get the scale length of Section. Length of the Section is calculated by 198 * summing the lengths of all Blocks in the section. If all Block lengths 199 * have not been entered, length will not be correct. 200 * 201 * @param meters true to return length in meters, false to use feet 202 * @param scale the scale; one of {@link jmri.Scale} 203 * @return the scale length 204 */ 205 public float getLengthF(boolean meters, Scale scale); 206 207 public int getLengthI(boolean meters, Scale scale); 208 209 /** 210 * Gets the actual length of the Section without any scaling 211 * 212 * @return the real length in millimeters 213 */ 214 public int getActualLength(); 215 216 /** 217 * Get Block by its Sequence number in the Section. 218 * 219 * @param seqNumber the sequence number 220 * @return the block or null if the sequence number is invalid 221 */ 222 @CheckForNull 223 public Block getBlockBySequenceNumber(int seqNumber); 224 225 /** 226 * Get the sequence number of a Block. 227 * 228 * @param b the block to get the sequence of 229 * @return the sequence number of b or -1 if b is not in the Section 230 */ 231 public int getBlockSequenceNumber(Block b); 232 233 /** 234 * Remove all Blocks, Block Listeners, and Entry Points 235 */ 236 public void removeAllBlocksFromSection(); 237 238 @CheckForNull 239 public Block getEntryBlock(); 240 241 @CheckForNull 242 public Block getNextBlock(); 243 244 @CheckForNull 245 public Block getExitBlock(); 246 247 public boolean containsBlock(Block b); 248 249 public boolean connectsToBlock(Block b); 250 251 public String getBeginBlockName(); 252 253 public String getEndBlockName(); 254 255 public void addToForwardList(EntryPoint ep); 256 257 public void addToReverseList(EntryPoint ep); 258 259 public void removeEntryPoint(EntryPoint ep); 260 261 public List<EntryPoint> getForwardEntryPointList(); 262 263 public List<EntryPoint> getReverseEntryPointList(); 264 265 public List<EntryPoint> getEntryPointList(); 266 267 public boolean isForwardEntryPoint(EntryPoint ep); 268 269 public boolean isReverseEntryPoint(EntryPoint ep); 270 271 /** 272 * Get the EntryPoint for entry from the specified Section for travel in 273 * specified direction. 274 * 275 * @param s the section 276 * @param dir the direction of travel; one of {@link #FORWARD} or 277 * {@link #REVERSE} 278 * @return the entry point or null if not found 279 */ 280 @CheckForNull 281 public EntryPoint getEntryPointFromSection(Section s, int dir); 282 283 /** 284 * Get the EntryPoint for exit to specified Section for travel in the 285 * specified direction. 286 * 287 * @param s the section 288 * @param dir the direction of travel; one of {@link #FORWARD} or 289 * {@link #REVERSE} 290 * @return the entry point or null if not found 291 */ 292 @CheckForNull 293 public EntryPoint getExitPointToSection(Section s, int dir); 294 295 /** 296 * Get the EntryPoint for entry from the specified Block for travel in the 297 * specified direction. 298 * 299 * @param b the block 300 * @param dir the direction of travel; one of {@link #FORWARD} or 301 * {@link #REVERSE} 302 * @return the entry point or null if not found 303 */ 304 @CheckForNull 305 public EntryPoint getEntryPointFromBlock(Block b, int dir); 306 307 /** 308 * Get the EntryPoint for exit to the specified Block for travel in the 309 * specified direction. 310 * 311 * @param b the block 312 * @param dir the direction of travel; one of {@link #FORWARD} or 313 * {@link #REVERSE} 314 * @return the entry point or null if not found 315 */ 316 @CheckForNull 317 public EntryPoint getExitPointToBlock(Block b, int dir); 318 319 /** 320 * Place direction sensors in SSL for all Signal Heads in this Section if 321 * the Sensors are not already present in the SSL. 322 * <p> 323 * Only anchor point block boundaries that have assigned signals are 324 * considered. Only turnouts that have assigned signals are considered. Only 325 * level crossings that have assigned signals are considered. Turnouts and 326 * anchor points without signals are counted, and reported in warning 327 * messages during this procedure, if there are any missing signals. 328 * <p> 329 * If this method has trouble, an error message is placed in the log 330 * describing the trouble. 331 * 332 * @return the number or errors placing sensors; 1 is returned if no 333 * direction sensor is defined for this section 334 */ 335 public int placeDirectionSensors(); 336 337 /** 338 * Validate the Section. This checks block connectivity, warns of redundant 339 * EntryPoints, and otherwise checks internal consistency of the Section. An 340 * appropriate error message is logged if a problem is found. This method 341 * assumes that Block Paths are correctly initialized. 342 * 343 * @return an error description or empty string if there are no errors 344 */ 345 public String validate(); 346 347 /** 348 * Set/reset the display to use alternate color for unoccupied blocks in 349 * this section. If Layout Editor panel is not present, Layout Blocks will 350 * not be present, and nothing will be set. 351 * 352 * @param set true to use alternate unoccupied color; false otherwise 353 */ 354 public void setAlternateColor(boolean set); 355 356 /** 357 * Set/reset the display to use alternate color for unoccupied blocks in 358 * this Section. If the Section already contains an active block, then the 359 * alternative color will be set from the active block, if no active block 360 * is found or we are clearing the alternative color then all the blocks in 361 * the Section will be set. If Layout Editor panel is not present, Layout 362 * Blocks will not be present, and nothing will be set. 363 * 364 * @param set true to use alternate unoccupied color; false otherwise 365 */ 366 public void setAlternateColorFromActiveBlock(boolean set); 367 368 /** 369 * Set the block values for blocks in this Section. 370 * 371 * @param name the value to set all blocks to 372 */ 373 public void setNameInBlocks(String name); 374 375 /** 376 * Set the block values for blocks in this Section. 377 * 378 * @param value the name to set block values to 379 */ 380 public void setNameInBlocks(Object value); 381 382 public void setNameFromActiveBlock(Object value); 383 384 /** 385 * Clear the block values for blocks in this Section. 386 */ 387 public void clearNameInUnoccupiedBlocks(); 388 389 /** 390 * Suppress the update of a memory variable when a block goes to unoccupied, 391 * so the text set above doesn't get wiped out. 392 * 393 * @param set true to suppress the update; false otherwise 394 */ 395 public void suppressNameUpdate(boolean set); 396 397 enum SectionType { 398 DYNAMICADHOC, // Created on an as required basis, not to be saved. 399 USERDEFINED, // Default Save all the information 400 SIGNALMASTLOGIC // Save only the name, blocks will be added by the signalmast logic 401 } 402 final public static SectionType USERDEFINED = SectionType.USERDEFINED; 403 final public static SectionType SIGNALMASTLOGIC = SectionType.SIGNALMASTLOGIC; 404 final public static SectionType DYNAMICADHOC = SectionType.DYNAMICADHOC; 405 406 /** 407 * Set Section Type. 408 * <ul> 409 * <li>USERDEFINED - Default Save all the information. 410 * <li>SIGNALMASTLOGIC - Save only the name, blocks will be added by the SignalMast logic. 411 * <li>DYNAMICADHOC - Created on an as required basis, not to be saved. 412 * </ul> 413 * @param type constant of section type. 414 */ 415 public void setSectionType(SectionType type); 416 417 /** 418 * Get Section Type. 419 * Defaults to USERDEFINED. 420 * @return constant of section type. 421 */ 422 public SectionType getSectionType(); 423 424}