001package jmri.jmrix.rps;
002
003import java.util.ArrayList;
004import javax.vecmath.Point3d;
005import jmri.Sensor;
006import jmri.implementation.AbstractSensor;
007
008/**
009 * Extend jmri.AbstractSensor for RPS systems.
010 * <p>
011 * System names are "RSpppp", where ppp is a representation of the region, for
012 * example "RS(0,0,0);(1,0,0);(1,1,0);(0,1,0)".
013 *
014 * @author Bob Jacobsen Copyright (C) 2007
015 */
016public class RpsSensor extends AbstractSensor
017        implements MeasurementListener {
018
019    public RpsSensor(String systemName, String prefix) {
020        super(systemName);
021        // create Region from all but prefix
022        region = new Region(systemName.substring(prefix.length() + 1)); // multichar prefix from memo
023        Model.instance().addRegion(region);
024    }
025
026    public RpsSensor(String systemName, String userName, String prefix) {
027        super(systemName, userName);
028        // create Region from all but prefix
029        region = new Region(systemName.substring(prefix.length() + 1)); // multichar prefix from memo
030        Model.instance().addRegion(region);
031    }
032
033    @Override
034    public void notify(Measurement r) {
035        Point3d p = new Point3d(r.getX(), r.getY(), r.getZ());
036        Integer id = Integer.valueOf(r.getReading().getId());
037
038        // ignore if code not OK
039        if (!r.isOkPoint()) {
040            return;
041        }
042
043        // ignore if not in Z fiducial volume
044        if (r.getZ() > 20 || r.getZ() < -20) {
045            return;
046        }
047
048        log.debug("starting {}", getSystemName());
049        if (region.isInside(p)) {
050            notifyInRegion(id);
051        } else {
052            notifyOutOfRegion(id);
053        }
054        if (!contents.isEmpty()) {
055            setOwnState(Sensor.ACTIVE);
056        } else {
057            setOwnState(Sensor.INACTIVE);
058        }
059    }
060
061    // if somebody outside sets state to INACTIVE, clear list
062    @Override
063    public void setOwnState(int state) {
064        if (state == Sensor.INACTIVE && (!contents.isEmpty())) {
065            contents = new ArrayList<>();
066        }
067        super.setOwnState(state);
068    }
069
070    Region getRegion() {
071        return region;
072    }
073
074    java.util.List<Integer> getContents() {
075        return contents;
076    }
077
078    void notifyInRegion(Integer id) {
079        // make sure region contains this Reading.getId();
080        if (!contents.contains(id)) {
081            contents.add(id);
082            notifyArriving(id);
083        }
084    }
085
086    void notifyOutOfRegion(Integer id) {
087        // make sure region does not contain this Reading.getId();
088        if (contents.contains(id)) {
089            contents.remove(id);
090            notifyLeaving(id);
091        }
092    }
093
094    transient Region region;
095    ArrayList<Integer> contents = new ArrayList<>();
096
097    /**
098     * Notify parameter listeners that a device has left the region covered by
099     * this sensor
100     * @param id Number of region being left
101     */
102    void notifyLeaving(Integer id) {
103        firePropertyChange("Leaving", null, id);
104    }
105
106    /**
107     * Notify parameter listeners that a device has entered the region covered
108     * by this sensor
109     * @param id Number of region being entered
110     */
111    void notifyArriving(Integer id) {
112        firePropertyChange("Arriving", null, id);
113    }
114
115    @Override
116    public void dispose() {
117        Model.instance().removeRegion(region);
118        super.dispose();
119    }
120
121    @Override
122    public void requestUpdateFromLayout() {
123    }
124
125    private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(RpsSensor.class);
126
127}