示例#1
0
文件: Engine.java 项目: jcooky/fecs
  private void initFloors() throws Exception {
    double y = 0;
    int numGroundFloors = 10;

    for (int i = numGroundFloors; i >= -1; --i) {
      if (i != 0) {
        Floor floor = new Floor(i);
        floor.setPosition(y);

        floors.put(FloorType.valueOf(i), floor);

        y += Floor.REAL_HEIGHT;
      }
    }
  }
示例#2
0
文件: Engine.java 项目: jcooky/fecs
/** Created by jcooky on 2014. 5. 12.. */
@Component("engine")
public class Engine implements Runnable, InitializingBean {
  public static final int STATE_STOP = 0b00, STATE_START = 0b01;
  public static final double CABIN_MOVE_THRESHOLD = 10 * 0.01; // 30cm in m
  public static final double REAL_TO_PIXEL_RATIO = Floor.PIXEL_HEIGHT / Floor.REAL_HEIGHT;

  @Autowired private UserInterface ui;

  private final Logger logger = LoggerFactory.getLogger(Engine.class);

  private Long lastUpdateTime = System.currentTimeMillis();

  /* gravity related constants */
  public static final Double earthGravity = 9.80665d;
  //  public static final Double[] gravityTable = new Double[]{earthGravity, 1.622d, 3.711d, 8.87d};
  // // 지구, 달, 화성, 금성
  public static final Map<String, Double> gravityTable =
      new HashMap<String, Double>() {
        {
          this.put("지구", earthGravity);
          this.put("달", 1.622d);
          this.put("화성", 3.711d);
          this.put("금성", 8.87d);
        }
      };

  private Double gravity = earthGravity;
  private Map<CabinType, Cabin> cabins = new EnumMap<>(CabinType.class);
  private Map<FloorType, Floor> floors = new EnumMap<>(FloorType.class);
  private Double cabinMass = 700d;
  private Integer state = CircumstanceType.DEFAULT.state() << 1;
  private Double forceBreak = 10000d;
  private Double motorOutput = 27000d;
  private Integer cabinLimitPeople = 12;
  private Double cabinLimitWeight = 1660d; // = cabinLimitPeople*passengerMass+cabinMass;
  private Double moreEnterProbability = 0.22;
  private Double passengerMass = 80d;
  private Set<Floor> pushedFloorSet = new HashSet<>(FloorType.values().length);

  @Override
  public void run() {

    try {
      if (Fecs.getApplicationContext() == null) return;

      Long currentTime = System.currentTimeMillis();
      double deltaTime = (currentTime - lastUpdateTime) * 0.001;

      if (getEngineState() == STATE_START) { // last bit is 1 = started
        int s = getCircumstanceState() - 1; // 0 is null state(error)
        if (s >= CircumstanceType.values().length || s < 0)
          throw new Exception("unstable state value with " + String.valueOf(s));
        Circumstance.get(CircumstanceType.values()[s])
            .setParameter("currentTime", currentTime)
            .setParameter("deltaTime", deltaTime)
            .trigger();
        for (Cabin cabin : cabins.values()) updateCabin(cabin, deltaTime);
      }

      lastUpdateTime = currentTime;

      draw();
    } catch (Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      try {
        Thread.sleep(1);
      } catch (InterruptedException e) {
        logger.error(e.getMessage(), e);
      }
      SwingUtilities.invokeLater(this);
    }
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    this.initFloors();
    this.initCabins();
  }

  private void draw() {
    Renderer renderer = ui.getRenderer();
    Graphics g = renderer.getGraphics();
    int fsize = g.getFont().getSize();
    JPanel target = ui.getDrawTarget();

    g.setColor(Color.GRAY);
    g.fillRect(0, 0, target.getWidth(), target.getHeight());

    Map<CabinType, Integer> xmap =
        new HashMap<CabinType, Integer>() {
          {
            this.put(CabinType.LEFT, Floor.PIXEL_WIDTH + 10);
            this.put(CabinType.RIGHT, Floor.PIXEL_WIDTH + 10 + Cabin.PIXEL_WIDTH + 30);
          }
        };

    for (CabinType type : cabins.keySet()) {
      Integer x = xmap.get(type);
      Cabin cabin = cabins.get(type);

      int passengers = cabin.getPassengers().size();
      double cabinY = cabin.getPosition() * REAL_TO_PIXEL_RATIO,
          cabinH = (double) cabin.PIXEL_HEIGHT,
          cabinW = (double) cabin.PIXEL_WIDTH;

      g.setColor(Color.WHITE);
      g.fillRect(x, (int) cabinY, (int) cabinW, (int) cabinH);
      g.setColor(Color.BLACK);
      g.drawRect(x, (int) cabinY, (int) cabinW, (int) cabinH);
      // cabin fullness
      g.drawString(
          passengers >= cabinLimitPeople ? passengers > cabinLimitPeople ? "초과" : "만원" : "",
          (int) (x + cabinW / 2.0 - fsize),
          (int) (cabinY + cabinH / 2.0 - fsize));
      // passengers on cabin
      g.drawString(
          String.format("%d명", passengers),
          (int) (x + cabinW / 2.0 - fsize * 2.0 / 2.0),
          (int) (cabinY + cabinH / 2.0));
      // cabin weight
      g.drawString(String.format("%.0fkg", mass(cabin)), x, (int) (cabinY + cabinH / 2.0 + fsize));
      // cabin speed
      g.drawString(
          String.format("%.1fm/s", Math.abs(cabin.getVelocity())),
          x,
          (int) (cabinY + cabinH / 2.0 + fsize * 2.0));
    }

    for (Floor floor : floors.values()) {
      int passengers = floor.getPassengers().size();
      double floorY = floor.getPosition() * REAL_TO_PIXEL_RATIO;
      g.setFont(Font.getFont(Font.SANS_SERIF));
      g.setColor(Color.WHITE);
      g.fillRect(1, (int) floorY, Floor.PIXEL_WIDTH, Floor.PIXEL_HEIGHT);
      g.setColor(Color.BLACK);
      g.drawRect(1, (int) floorY, Floor.PIXEL_WIDTH, Floor.PIXEL_HEIGHT);
      g.drawString(floor.getNum() + "층", 1, (int) floorY + 15);
      g.drawString(
          Integer.toString(passengers),
          (int) (1 + (double) (Floor.PIXEL_WIDTH) / 2.0 - (double) fsize / 2.0),
          (int) (floorY + (double) Floor.PIXEL_HEIGHT / 2.0));
    }
    if (state >> 1 == CircumstanceType.FIRE.state()) {
      Floor firedFloor = (Floor) Circumstance.get(CircumstanceType.FIRE).getParameter("floor");
      if (null != firedFloor)
        g.drawString(
            "화재",
            Floor.PIXEL_WIDTH / 2 - fsize,
            (int)
                (firedFloor.getPosition() * REAL_TO_PIXEL_RATIO
                    + (double) Floor.PIXEL_HEIGHT / 2.0
                    + fsize * 2.0));
    }
    renderer.flush();
  }

  public void updateCabin(Cabin cabin, double accel, double deltaTime) {
    if (deltaTime > 0.2) return;
    double vi = cabin.getVelocity(), vf = vi + accel * deltaTime; // vf=vi+ a*dt
    if (Math.abs(vf) > 20) vf = 0d;
    double ds = 0.5 * deltaTime * (vf + vi);
    cabin.setPosition(
        cabin.getPosition() + ds); // sf=si+integral(dv=vf-vi)=si+dt*(vf-vi)=si+dt*(a*dt)=si+a*dt^2
    cabin.setVelocity(vf);

    double min = floors.get(FloorType.TENTH).getPosition(),
        max = floors.get(FloorType.UNDER_FIRST).getPosition();
    if (cabin.getPosition() > max) {
      cabin.setPosition(max);
    }
    if (cabin.getPosition() < min) {
      cabin.setPosition(min);
    }
  }

  public void updateCabin(Cabin cabin, double deltaTime) {
    if (deltaTime > 0.2) return;
    if (cabin.isOn()) {
      switch (cabin.getState()) {
        case MOVE:
          double vector = cabin.getVector();
          int vectorUnit = (int) (vector / Math.abs(vector));
          double motor = motorOutput * earthGravity * deltaTime; // Nm/s (weight) -> kgfm
          if (motor <= gravity) {
            logger.debug("motor is too weak or gravity is too strong.");
            motor = gravity;
          }
          Floor target = cabin.getTarget();
          double leftVector = target.getPosition() - cabin.getPosition();
          int leftVectorUnit = (int) (leftVector / Math.abs(leftVector));
          double accel = motor / mass(cabin) * leftVectorUnit;
          if (Math.abs(cabin.getVelocity()) > 1)
            accel *= Math.abs(vector * 0.5) < Math.abs(leftVector) ? 1 : -1; // brake on half point
          if (Double.isNaN(accel)) {
            accel = vectorUnit;
          }
          //          logger.debug(String.format("%f -> %f (%f) : %f",cabin.getPosition(),
          // target.getPosition(),vector,accel));
          //          logger.debug(String.format("%s->%d, %f, %f,
          // %f",cabin.getName(),target.getNum(),accel,leftVector,vector*0.5));
          updateCabin(cabin, accel, deltaTime);

          if (Math.abs(leftVector) < CABIN_MOVE_THRESHOLD) { // arrive
            cabin.setPosition(target.getPosition());
            cabin.stop();
            //            cabin.getQueue().remove(target);
            logger.debug(String.format("%s->%d done", cabin.getName(), target.getNum()));
          }
          break;
        case STOP:
          logger.info("cabin({}) arrived", cabin.getName());

          for (Floor floor : floors.values()) {
            if (cabin.getPosition() == floor.getPosition()) {
              logger.debug("on {}", floor);
              Iterator<Passenger> it = cabin.getPassengers().iterator();
              while (it.hasNext()) {
                Passenger p = it.next();
                if (p.getDest().equals(floor.getNum())) {
                  p.setState(Passenger.State.NO_WAIT);
                  it.remove();
                  floor.getPassengers().add(p);
                }
              }
              cabin.getQueue().remove(floor);
            }
          }

          if (cabin.getQueue().size() > 0) cabin.move(); // to next queued floor
          break;
      }
    }
  }

  private void initCabins() {
    for (CabinType t : CabinType.values()) {
      Cabin cabin = new Cabin(t.toString());
      cabin.setPosition(floors.get(FloorType.TENTH).getPosition());
      cabins.put(t, cabin);
    }
  }

  private void initFloors() throws Exception {
    double y = 0;
    int numGroundFloors = 10;

    for (int i = numGroundFloors; i >= -1; --i) {
      if (i != 0) {
        Floor floor = new Floor(i);
        floor.setPosition(y);

        floors.put(FloorType.valueOf(i), floor);

        y += Floor.REAL_HEIGHT;
      }
    }
  }

  public Double mass(Cabin cabin) {
    return cabinMass + passengerMass * cabin.getPassengers().size();
  }

  public Double getGravity() {
    return gravity;
  }

  public void setGravity(Double gravity) {
    this.gravity = gravity;
  }

  public Double getCabinMass() {
    return cabinMass;
  }

  public void setCabinMass(Double cabinMass) {
    this.cabinMass = cabinMass;
  }

  public void setState(Integer state) {
    this.state = state;
  }

  public void setEngineState(Integer state) {
    this.state = (getCircumstanceState() << 1) | getEngineState(state);
  }

  public void setCircumstanceState(Integer state) {
    this.state = (state << 1) | getEngineState();
  }

  public Integer getState() {
    return state;
  }

  public Integer getEngineState(Integer s) {
    return s & 1;
  }

  public Integer getEngineState() {
    return getEngineState(state);
  }

  public Integer getCircumstanceState(Integer s) {
    return (s & ~1) >> 1;
  }

  public Integer getCircumstanceState() {
    return getCircumstanceState(state);
  }

  public Double getForceBreak() {
    return forceBreak;
  }

  public void setForceBreak(Double forceBreak) {
    this.forceBreak = forceBreak;
  }

  public Double getMotorOutput() {
    return motorOutput;
  }

  public void setMotorOutput(Double motorOutput) {
    this.motorOutput = motorOutput;
  }

  public Integer getCabinLimitPeople() {
    return cabinLimitPeople;
  }

  public void setCabinLimitPeople(Integer cabinLimitPeople) {
    this.cabinLimitPeople = cabinLimitPeople;
  }

  public Double getCabinLimitWeight() {
    return cabinLimitWeight;
  }

  public void setCabinLimitWeight(Double cabinLimitWeight) {
    this.cabinLimitWeight = cabinLimitWeight;
  }

  public Double getMoreEnterProbability() {
    return moreEnterProbability;
  }

  public void setMoreEnterProbability(Double moreEnterProbability) {
    this.moreEnterProbability = moreEnterProbability;
  }

  public Double getPassengerMass() {
    return passengerMass;
  }

  public void setPassengerMass(Double passengerMass) {
    this.passengerMass = passengerMass;
  }

  public Map<FloorType, Floor> getFloors() {
    return floors;
  }

  public Map<CabinType, Cabin> getCabins() {
    return cabins;
  }

  public Set<Floor> getPushedFloorSet() {
    return pushedFloorSet;
  }
}