Package org.nlogo.agent

Source Code of org.nlogo.agent.Turtle3D

// (C) Uri Wilensky. https://github.com/NetLogo/NetLogo

package org.nlogo.agent;

import org.nlogo.api.AgentException;
import org.nlogo.api.AgentVariableNumbers;
import org.nlogo.api.AgentVariables;
import org.nlogo.api.Color;
import org.nlogo.api.Dump;
import org.nlogo.api.I18N;
import org.nlogo.api.LogoList;
import org.nlogo.api.Vect;

import java.util.List;

public final strictfp class Turtle3D
    extends Turtle
    implements Agent3D, org.nlogo.api.Turtle3D {
  public static final int VAR_WHO3D = AgentVariableNumbers.VAR_WHO3D;
  public static final int VAR_COLOR3D = AgentVariableNumbers.VAR_COLOR3D;
  public static final int VAR_HEADING3D = AgentVariableNumbers.VAR_HEADING3D;
  public static final int VAR_PITCH3D = AgentVariableNumbers.VAR_PITCH3D;
  public static final int VAR_ROLL3D = AgentVariableNumbers.VAR_ROLL3D;
  public static final int VAR_XCOR3D = AgentVariableNumbers.VAR_XCOR3D;
  public static final int VAR_YCOR3D = AgentVariableNumbers.VAR_YCOR3D;
  public static final int VAR_ZCOR3D = AgentVariableNumbers.VAR_ZCOR3D;
  static final int VAR_SHAPE3D = AgentVariableNumbers.VAR_SHAPE3D;
  public static final int VAR_LABEL3D = AgentVariableNumbers.VAR_LABEL3D;
  private static final int VAR_LABELCOLOR3D = AgentVariableNumbers.VAR_LABELCOLOR3D;
  static final int VAR_BREED3D = AgentVariableNumbers.VAR_BREED3D;
  private static final int VAR_HIDDEN3D = AgentVariableNumbers.VAR_HIDDEN3D;
  private static final int VAR_SIZE3D = AgentVariableNumbers.VAR_SIZE3D;
  private static final int VAR_PENSIZE3D = AgentVariableNumbers.VAR_PENSIZE3D;
  private static final int VAR_PENMODE3D = AgentVariableNumbers.VAR_PENMODE3D;

  void initvars(Number xcor, Number ycor, AgentSet breed) {
    LAST_PREDEFINED_VAR = VAR_PENMODE3D;
    NUMBER_PREDEFINED_VARS = LAST_PREDEFINED_VAR + 1;

    variables[VAR_COLOR3D] = Color.BoxedBlack();
    heading = 0;
    variables[VAR_HEADING3D] = World.ZERO;
    this.xcor = xcor.doubleValue();
    if (xcor instanceof Double) {
      variables[VAR_XCOR3D] = xcor;
    }
    this.ycor = ycor.doubleValue();
    if (ycor instanceof Double) {
      variables[VAR_YCOR3D] = ycor;
    }
    variables[VAR_SHAPE3D] = world.turtleBreedShapes.breedShape(breed);
    variables[VAR_LABEL3D] = "";
    variables[VAR_LABELCOLOR3D] = Color.BoxedWhite();
    variables[VAR_BREED3D] = breed;
    variables[VAR_HIDDEN3D] = Boolean.FALSE;
    variables[VAR_SIZE3D] = World.ONE;
    variables[VAR_PENSIZE3D] = World.ONE;
    variables[VAR_PENMODE3D] = PEN_UP;
  }

  public Turtle3D(World3D world, AgentSet breed, Number xcor, Number ycor, Number zcor) {
    this(world, breed, xcor, ycor, zcor, true);
  }

  private Turtle3D(World3D world, AgentSet breed, Number xcor, Number ycor, Number zcor, boolean getId) {
    super(world);

    variables = new Object[world.getVariablesArraySize(this, breed)];
    if (getId) {
      id(world.newTurtleId());
      world.turtles().add(this);
    }
    initvars(xcor, ycor, breed);

    for (int i = LAST_PREDEFINED_VAR + 1; i < variables.length; i++) {
      variables[i] = World.ZERO;
    }
    if (breed != world.turtles()) {
      breed.add(this);
    }

    variables[VAR_PITCH3D] = World.ZERO;
    variables[VAR_ROLL3D] = World.ZERO;
    this.zcor = zcor.doubleValue();
    if (zcor instanceof Double) {
      variables[VAR_ZCOR3D] = zcor;
    }
    getPatchHere().addTurtle(this);
  }

  Turtle3D(World world) {
    super(world);
  }

  Turtle3D(World world, long id) {
    this((World3D) world, world.turtles(),
        World.ZERO, World.ZERO, World.ZERO,
        false);
    id(id);
    world.turtles().add(this);
  }

  @Override
  public Turtle hatch() {
    Turtle3D child = new Turtle3D(world);
    child.heading = heading;
    child.xcor = xcor;
    child.ycor = ycor;
    child.zcor = zcor;
    child.variables = variables.clone();
    child.id(world.newTurtleId());
    world.turtles().add(child);
    if (getBreed() != world.turtles()) {
      getBreed().add(child);
    }
    child.getPatchHere().addTurtle(child);
    return child;
  }

  @Override
  public Patch getPatchAtOffsets(double dx, double dy)
      throws AgentException {
    Patch target = ((World3D) world).getPatchAt(xcor + dx, ycor + dy, zcor);
    if (target == null) {
      throw new AgentException("Cannot get patch beyond limits of current world.");
    }
    return target;
  }

  public Patch3D getPatchAtOffsets(double dx, double dy, double dz)
      throws AgentException {
    Patch3D target = ((World3D) world).getPatchAt(xcor + dx, ycor + dy, zcor + dz);
    if (target == null) {
      throw new AgentException("Cannot get patch beyond limits of current world.");
    }
    return target;
  }

  public Patch getPatchAtPoint(List<Double> point)
      throws AgentException {
    double dx = point.get(0).doubleValue();
    double dy = point.get(1).doubleValue();
    double dz = point.size() == 3 ? point.get(2).doubleValue() : 0;
    return getPatchAtOffsets(dx, dy, dz);
  }

  // note this is very similar to
  // World.getPatchAtDistanceAndHeading() - ST 9/3/03
  @Override
  public void jump(double distance) {
    double pitchRadians = StrictMath.toRadians(pitch());
    double sin = StrictMath.sin(pitchRadians);
    double distProj = distance * StrictMath.cos(pitchRadians);
    if (StrictMath.abs(sin) < org.nlogo.api.Constants.Infinitesimal()) {
      sin = 0;
    }
    if (StrictMath.abs(distProj) < org.nlogo.api.Constants.Infinitesimal()) {
      distProj = 0;
    }

    double headingRadians = StrictMath.toRadians(heading());
    double cosProj = StrictMath.cos(headingRadians);
    double sinProj = StrictMath.sin(headingRadians);

    if (StrictMath.abs(cosProj) < org.nlogo.api.Constants.Infinitesimal()) {
      cosProj = 0;
    }
    if (StrictMath.abs(sinProj) < org.nlogo.api.Constants.Infinitesimal()) {
      sinProj = 0;
    }

    xyandzcor(xcor + (distProj * sinProj),
        ycor + (distProj * cosProj),
        zcor + (distance * sin));

  }

  @Override
  public Patch getPatchHere() {
    if (currentPatch == null) {
      //turtles cannot leave the world, so xcor and ycor will always be valid
      //so assume we dont have to access the Topologies
      currentPatch = ((World3D) world).getPatchAtWrap(xcor, ycor, zcor);
    }
    return currentPatch;
  }

  @Override
  public Object getTurtleVariable(int vn) {
    switch (vn) {
      case VAR_WHO3D:
        if (variables[VAR_WHO3D] == null) {
          variables[VAR_WHO3D] = Double.valueOf(id);
        }
        break;
      case VAR_HEADING3D:
        if (variables[VAR_HEADING3D] == null) {
          variables[VAR_HEADING3D] = Double.valueOf(heading);
        }
        break;
      case VAR_XCOR3D:
        if (variables[VAR_XCOR3D] == null) {
          variables[VAR_XCOR3D] = Double.valueOf(xcor);
        }
        break;
      case VAR_YCOR3D:
        if (variables[VAR_YCOR3D] == null) {
          variables[VAR_YCOR3D] = Double.valueOf(ycor);
        }
        break;
      case VAR_ZCOR3D:
        if (variables[VAR_ZCOR3D] == null) {
          variables[VAR_ZCOR3D] = Double.valueOf(zcor);
        }
        break;
      default:
        break;
    }
    return variables[vn];
  }

  @Override
  public double getTurtleVariableDouble(int vn) {
    switch (vn) {
      case VAR_HEADING3D:
        return heading;
      case VAR_PITCH3D:
        return pitch();
      case VAR_ROLL3D:
        return roll();
      case VAR_XCOR3D:
        return xcor;
      case VAR_YCOR3D:
        return ycor;
      case VAR_ZCOR3D:
        return zcor;
      case VAR_SIZE3D:
        return size();
      case VAR_PENSIZE3D:
        return penSize();
      default:
        throw new IllegalArgumentException
            (vn + " is not a double variable");
    }
  }

  @Override
  public void setTurtleVariable(int vn, double value)
      throws AgentException {
    switch (vn) {
      case VAR_HEADING3D:
        heading(value);
        break;
      case VAR_XCOR3D:
        xcor(value);
        break;
      case VAR_YCOR3D:
        ycor(value);
        break;
      case VAR_SIZE3D:
        size(value);
        break;
      case VAR_PENSIZE3D:
        penSize(value);
        break;
      case VAR_PITCH3D:
        pitch(value);
        break;
      case VAR_ROLL3D:
        roll(value);
        break;
      case VAR_ZCOR3D:
        zcor(value);
        break;
      case VAR_WHO3D:
        throw new AgentException("you can't change a turtle's who number");
      default:
        throw new IllegalArgumentException
            (vn + " is not a double variable");
    }
  }

  @Override
  public void setTurtleVariable(int vn, Object value)
      throws AgentException {
    if (vn > LAST_PREDEFINED_VAR) {
      variables[vn] = value;
    } else {
      switch (vn) {
        case VAR_COLOR3D:
          if (value instanceof Double) {
            colorDouble((Double) value);
          } else if (value instanceof LogoList) {
            color((LogoList) value, VAR_COLOR3D);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;
        case VAR_HEADING3D:
          if (value instanceof Double) {
            heading((Double) value);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;
        case VAR_XCOR3D:
          if (value instanceof Double) {
            xcor((Double) value);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;
        case VAR_YCOR3D:
          if (value instanceof Double) {
            ycor((Double) value);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;
        case VAR_SHAPE3D:
          if (value instanceof String) {
            String newShape = world.checkTurtleShapeName((String) value);
            if (newShape == null) {
              throw new AgentException
                  ("\"" + (String) value + "\" is not a currently defined shape");
            }
            shape(newShape);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                String.class, value);
          }
          break;
        case VAR_LABEL3D:
          label(value);
          break;
        case VAR_LABELCOLOR3D:
          if (value instanceof Number) {
            labelColor(((Number) value).doubleValue());
          } else if (value instanceof LogoList) {
            labelColor((LogoList) value, VAR_LABELCOLOR3D);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;
        case VAR_BREED3D:
          if (value instanceof AgentSet) {
            AgentSet breed = (AgentSet) value;
            if (breed != world.turtles() && !world.isBreed(breed)) {
              throw new AgentException(I18N.errorsJ().get("org.nlogo.agent.Turtle.cantSetBreedToNonBreedAgentSet"));
            }
            setBreed(breed);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                AgentSet.class, value);
          }
          break;
        case VAR_HIDDEN3D:
          if (value instanceof Boolean) {
            hidden(((Boolean) value).booleanValue());
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Boolean.class, value);
          }
          break;
        case VAR_SIZE3D:
          if (value instanceof Number) {
            size(((Number) value).doubleValue());
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;
        case VAR_PENMODE3D:
          if (value instanceof String) {
            penMode((String) value);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                String.class, value);
          }
          break;

        case VAR_PENSIZE3D:
          if (value instanceof Number) {
            penSize(((Number) value).doubleValue());
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;

        case VAR_WHO3D:
          throw new AgentException("you can't change a turtle's ID number");

        case VAR_PITCH3D:
          if (value instanceof Number) {
            pitch(((Number) value).doubleValue());
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;
        case VAR_ROLL3D:
          if (value instanceof Number) {
            roll(((Number) value).doubleValue());
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;
        case VAR_ZCOR3D:
          if (value instanceof Double) {
            zcor((Double) value);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitTurtleVariables(true)[vn],
                Double.class, value);
          }
          break;
        default:
          return;
      }
    }
  }

  public double pitch() {
    return ((Double) variables[VAR_PITCH3D]).doubleValue();
  }

  public void pitch(double pitch) {
    double originalPitch = this.pitch();
    if (pitch < 0 || pitch >= 360) {
      pitch = ((pitch % 360) + 360) % 360;
    }
    variables[VAR_PITCH3D] = Double.valueOf(pitch);
    if (this == world.observer().targetAgent()) {
      world.observer().updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleOrientationChanged(heading, pitch, this.roll(),
          heading, originalPitch, this.roll());
    }
  }

  public double roll() {
    return ((Double) variables[VAR_ROLL3D]).doubleValue();
  }

  public void roll(double roll) {
    double originalRoll = this.roll();
    if (roll < 0 || roll >= 360) {
      roll = ((roll % 360) + 360) % 360;
    }
    variables[VAR_ROLL3D] = Double.valueOf(roll);
    if (this == world.observer().targetAgent()) {
      world.observer().updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleOrientationChanged(this.heading(), this.pitch(), roll,
          this.heading(), this.pitch(), originalRoll);
    }
  }

  public void headingPitchAndRoll(double heading, double pitch, double roll) {
    double originalHeading = this.heading();
    double originalPitch = this.pitch();
    double originalRoll = this.roll();

    if (roll < 0 || roll >= 360) {
      roll = ((roll % 360) + 360) % 360;
    }
    if (pitch < 0 || pitch >= 360) {
      pitch = ((pitch % 360) + 360) % 360;
    }
    if (heading < 0 || heading >= 360) {
      heading = ((heading % 360) + 360) % 360;
    }
    variables[VAR_PITCH3D] = Double.valueOf(pitch);
    variables[VAR_ROLL3D] = Double.valueOf(roll);
    this.heading = heading;
    variables[VAR_HEADING] = null;
    if (this == world.observer().targetAgent()) {
      world.observer().updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleOrientationChanged(heading, pitch, roll,
          originalHeading, originalPitch, originalRoll);
    }
  }

  @Override
  void drawLine(double x0, double y0, double x1, double y1) {
    if (penMode().equals(PEN_DOWN) && (x0 != x1 || y0 != y1)) {
      ((World3D) world).drawLine
          (x0, y0, zcor, x1, y1, zcor, color(), penSize());
    }
  }

  void drawLine(double x0, double y0, double z0, double x1, double y1, double z1) {
    if (penMode().equals(PEN_DOWN) && (x0 != x1 || y0 != y1 || z0 != z1)) {
      ((World3D) world).drawLine(x0, y0, z0, x1, y1, z1, color(), penSize());
    }
  }

  public double shortestPathZ(double z) {
    if (!penMode().equals(PEN_DOWN)) {
      return z;
    }

    World3D w = (World3D) world;

    z = ((Topology3D) world.getTopology()).wrapZ(z);

    double zprime;

    if (z > zcor) {
      zprime = z - w.worldDepth();
    } else {
      zprime = z + w.worldDepth();
    }

    if (StrictMath.abs(z - zcor) > StrictMath.abs(zprime - zcor)) {
      z = zprime;
    }

    return z;
  }

  @Override
  public void moveTo(Agent otherAgent)
      throws AgentException {
    double x, y, z;
    if (otherAgent instanceof Turtle) {
      Turtle3D t = (Turtle3D) otherAgent;
      x = t.xcor();
      y = t.ycor();
      z = t.zcor();
    } else {
      Patch3D p = (Patch3D) otherAgent;
      x = p.pxcor;
      y = p.pycor;
      z = p.pzcor;
    }

    xyandzcor(shortestPathX(x), shortestPathY(y), shortestPathZ(z));
  }

  @Override
  public void moveToPatchCenter() {
    Patch3D p = (Patch3D) getPatchHere();
    double x = p.pxcor;
    double y = p.pycor;
    double z = p.pzcor;
    double oldX = this.xcor;
    double oldY = this.ycor;
    double oldZ = this.zcor;
    drawLine(oldX, oldY, oldZ, x, y, z);
    if (x != oldX || y != oldY || z != oldZ) {
      this.xcor = x;
      this.ycor = y;
      this.zcor = z;
      variables[VAR_XCOR3D] = p.variables[Patch3D.VAR_PXCOR3D];
      variables[VAR_YCOR3D] = p.variables[Patch3D.VAR_PYCOR3D];
      variables[VAR_ZCOR3D] = p.variables[Patch3D.VAR_PZCOR3D];
      Observer observer = world.observer();
      if (this == observer.targetAgent()) {
        observer.updatePosition();
      }
      if (world.tieManager.tieCount > 0) {
        ((TieManager3D) world.tieManager).turtleMoved(this, x, y, z, oldX, oldY, oldZ);
      }
    }
  }

  @Override
  public void xcor(double xcor)
      throws AgentException {
    Patch originalPatch = getPatchHere();

    double oldX = this.xcor;

    drawLine(oldX, ycor, shortestPathX(xcor), ycor);

    this.xcor = world.getTopology().wrapX(xcor);

    variables[VAR_XCOR3D] = null;
    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    Observer observer = world.observer();
    if (this == observer.targetAgent()) {
      observer.updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleMoved(xcor, ycor, zcor, oldX, ycor, zcor);
    }
  }

  @Override
  public void xcor(Double xcor)
      throws AgentException {
    Patch originalPatch = getPatchHere();
    double x = xcor.doubleValue();
    double wrapped = world.getTopology().wrapX(x);
    double oldX = this.xcor;

    drawLine(this.xcor, ycor, shortestPathX(x), ycor);

    this.xcor = wrapped;
    if (x == wrapped) {
      variables[VAR_XCOR3D] = xcor;
    } else {
      variables[VAR_XCOR3D] = null;
    }
    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    Observer observer = world.observer();
    if (this == observer.targetAgent()) {
      observer.updatePosition();
    }

    if (world.tieManager.tieCount > 0) {
      turtleMoved(x, ycor, zcor, oldX, ycor, zcor);
    }
  }

  double zcor;

  public double zcor() {
    return zcor;
  }

  public void zcor(double zcor) {
    Patch originalPatch = getPatchHere();
    double oldZ = this.zcor;
    World3D w = (World3D) world;
    double z = Topology.wrap(zcor, w.minPzcor() - 0.5, w.maxPzcor() + 0.5);

    drawLine(xcor, ycor, this.zcor, xcor, ycor, shortestPathZ(zcor));

    this.zcor = z;

    variables[VAR_ZCOR3D] = null;
    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    if (world.tieManager.tieCount > 0) {
      turtleMoved(xcor, ycor, zcor, xcor, ycor, oldZ);
    }
  }

  public void zcor(Double zcor) {
    Patch originalPatch = getPatchHere();
    double oldZ = this.zcor;
    double z = zcor.doubleValue();
    World3D w = (World3D) world;
    double wrapped = Topology.wrap(zcor.doubleValue(), w.minPzcor() - 0.5, w.maxPzcor() + 0.5);

    drawLine(xcor, ycor, this.zcor, xcor, ycor, shortestPathZ(z));

    this.zcor = wrapped;

    if (z == wrapped) {
      variables[VAR_ZCOR3D] = zcor;
    } else {
      variables[VAR_ZCOR3D] = null;
    }
    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    if (world.tieManager.tieCount > 0) {
      turtleMoved(xcor, ycor, z, xcor, ycor, oldZ);
    }
  }

  @Override
  public void ycor(double ycor)
      throws AgentException {
    Patch originalPatch = getPatchHere();

    double oldY = this.ycor;

    drawLine(xcor, oldY, xcor, shortestPathY(ycor));

    this.ycor = world.getTopology().wrapY(ycor);

    variables[VAR_YCOR3D] = null;
    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    Observer observer = world.observer();
    if (this == observer.targetAgent()) {
      observer.updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleMoved(xcor, ycor, zcor, xcor, oldY, zcor);
    }
  }

  @Override
  public void ycor(Double ycor)
      throws AgentException {
    Patch originalPatch = getPatchHere();
    double oldY = this.ycor;
    double y = ycor.doubleValue();
    double wrapped = world.getTopology().wrapY(y);

    drawLine(xcor, this.ycor, xcor, shortestPathY(y));

    this.ycor = wrapped;
    if (y == wrapped) {
      variables[VAR_YCOR3D] = ycor;
    } else {
      variables[VAR_YCOR3D] = null;
    }
    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    Observer observer = world.observer();
    if (this == observer.targetAgent()) {
      observer.updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleMoved(xcor, y, zcor, xcor, oldY, zcor);
    }
  }

  @Override
  public void xandycor(double xcor, double ycor)
      throws AgentException {
    Patch originalPatch = getPatchHere();
    double oldX = this.xcor;
    double oldY = this.ycor;
    double newX = world.getTopology().wrapX(xcor);
    double newY = world.getTopology().wrapY(ycor);
    drawLine(this.xcor, this.ycor, xcor, ycor);

    this.xcor = newX;
    this.ycor = newY;

    variables[VAR_XCOR3D] = null;
    variables[VAR_YCOR3D] = null;
    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    Observer observer = world.observer();
    if (this == observer.targetAgent()) {
      observer.updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleMoved(xcor, ycor, zcor, oldX, oldY, zcor);
    }
  }

  @Override
  public void xandycor(Double xcor, Double ycor)
      throws AgentException {
    Patch originalPatch = getPatchHere();
    double oldX = this.xcor;
    double oldY = this.ycor;

    double x = xcor.doubleValue();
    double y = ycor.doubleValue();

    double wrappedX = world.getTopology().wrapX(x);
    double wrappedY = world.getTopology().wrapY(y);

    drawLine(this.xcor, this.ycor, x, y);

    this.xcor = wrappedX;
    this.ycor = wrappedY;
    variables[VAR_XCOR3D] = (x == wrappedX) ? xcor : null;
    variables[VAR_YCOR3D] = (y == wrappedY) ? ycor : null;
    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    Observer observer = world.observer();
    if (this == observer.targetAgent()) {
      observer.updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleMoved(x, y, zcor, oldX, oldY, zcor);
    }
  }

  public void xyandzcor(double xcor, double ycor, double zcor) {
    Patch originalPatch = getPatchHere();
    double oldX = this.xcor;
    double oldY = this.ycor;
    double oldZ = this.zcor;

    World3D w = (World3D) world;
    double newX = Topology.wrap(xcor, w.minPxcor() - 0.5, w.maxPxcor() + 0.5);
    double newY = Topology.wrap(ycor, w.minPycor() - 0.5, w.maxPycor() + 0.5);
    double newZ = Topology.wrap(zcor, w.minPzcor() - 0.5, w.maxPzcor() + 0.5);

    drawLine(this.xcor, this.ycor, this.zcor, xcor, ycor, zcor);

    this.xcor = newX;
    this.ycor = newY;
    this.zcor = newZ;

    variables[VAR_XCOR3D] = null;
    variables[VAR_YCOR3D] = null;
    variables[VAR_ZCOR3D] = null;

    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    Observer observer = world.observer();
    if (this == observer.targetAgent()) {
      observer.updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleMoved(xcor, ycor, zcor, oldX, oldY, oldZ);
    }
  }

  public void xyandzcor(Double xcor, Double ycor, Double zcor) {
    Patch originalPatch = getPatchHere();
    double oldX = this.xcor;
    double oldY = this.ycor;
    double oldZ = this.zcor;

    double x = xcor.doubleValue();
    double y = ycor.doubleValue();
    double z = zcor.doubleValue();
    World3D w = (World3D) world;
    double wrappedX = Topology.wrap(x, w.minPxcor() - 0.5, w.maxPxcor() + 0.5);
    double wrappedY = Topology.wrap(y, w.minPycor() - 0.5, w.maxPycor() + 0.5);
    double wrappedZ = Topology.wrap(z, w.minPzcor() - 0.5, w.maxPzcor() + 0.5);

    drawLine(this.xcor, this.ycor, this.zcor, x, y, z);

    this.xcor = wrappedX;
    this.ycor = wrappedY;
    this.zcor = wrappedZ;
    variables[VAR_XCOR3D] = (x == wrappedX) ? xcor : null;
    variables[VAR_YCOR3D] = (y == wrappedY) ? ycor : null;
    variables[VAR_ZCOR3D] = (z == wrappedZ) ? zcor : null;
    currentPatch = null;
    Patch targetPatch = getPatchHere();
    if (originalPatch != targetPatch) {
      originalPatch.removeTurtle(this);
      targetPatch.addTurtle(this);
    }
    Observer observer = world.observer();
    if (this == observer.targetAgent()) {
      observer.updatePosition();
    }
    if (world.tieManager.tieCount > 0) {
      turtleMoved(x, y, z, oldX, oldY, oldZ);
    }
  }

  @Override
  public void home() {
    xyandzcor(World.ZERO, World.ZERO, World.ZERO);
  }

  @Override
  public void face(Agent agent, boolean wrap) {
    double newHeading, newPitch;
    try {
      newHeading = world.protractor().towards(this, agent, wrap); // true = wrap
    } catch (AgentException ex) {
      newHeading = heading();
    }
    try {
      newPitch = world.protractor().towardsPitch(this, agent, wrap);
    } catch (AgentException ex) {
      newPitch = pitch();
    }
    headingPitchAndRoll(newHeading, newPitch, this.roll());
  }

  public void face(double x, double y, double z, boolean wrap) {
    double newHeading = heading();
    double newPitch = pitch();
    try {
      newHeading = world.protractor().towards(this, x, y, wrap);
    } catch (AgentException ex) {
      // AgentException here means we tried to calculate the heading from
      // an agent to itself, or to an agent at the exact same position.
      // Since face is nice, it just ignores the exception and doesn't change
      // the callers heading. - AZS 6/22/05
      org.nlogo.util.Exceptions.ignore(ex);
    }
    try {
      newPitch = world.protractor().towardsPitch(this, x, y, z, wrap);
    } catch (AgentException ex) {
      org.nlogo.util.Exceptions.ignore(ex);
    }

    headingPitchAndRoll(newHeading, newPitch, roll());
  }

  @Override
  public double dx() {
    return StrictMath.cos(StrictMath.toRadians(pitch())) *
        StrictMath.sin(StrictMath.toRadians(heading()));
  }

  @Override
  public double dy() {
    return StrictMath.cos(StrictMath.toRadians(pitch())) *
        StrictMath.cos(StrictMath.toRadians(heading()));
  }

  public double dz() {
    return StrictMath.sin(StrictMath.toRadians(pitch()));
  }

  @Override
  public String shape() {
    return (String) variables[VAR_SHAPE3D];
  }

  @Override
  public void shape(String shape) {
    variables[VAR_SHAPE3D] = shape;
  }

  @Override
  public Object label() {
    return variables[VAR_LABEL3D];
  }

  @Override
  public String labelString() {
    return Dump.logoObject(variables[VAR_LABEL3D]);
  }

  @Override
  public void label(Object label) {
    variables[VAR_LABEL3D] = label;
  }

  @Override
  public Object labelColor() {
    return variables[VAR_LABELCOLOR3D];
  }

  @Override
  public void labelColor(double labelColor) {
    variables[VAR_LABELCOLOR3D] = Double.valueOf(Color.modulateDouble(labelColor));
  }

  @Override
  public AgentSet getBreed() {
    return (AgentSet) variables[VAR_BREED3D];
  }

  /**
   * This version of setBreed properly resets the global breed AgentSets
   * Caller should ensure that the turtle isn't a link (links aren't
   * allowed to change breed).
   */
  @Override
  public void setBreed(AgentSet breed) {
    AgentSet oldBreed = null;
    if (variables[VAR_BREED3D] instanceof AgentSet) {
      oldBreed = (AgentSet) variables[VAR_BREED3D];
      if (breed == oldBreed) {
        return;
      }
      if (oldBreed != world.turtles()) {
        ((AgentSet) variables[VAR_BREED3D]).remove(agentKey());
      }
    }
    if (breed != world.turtles()) {
      breed.add(this);
    }
    variables[VAR_BREED3D] = breed;
    shape(world.turtleBreedShapes.breedShape(breed));
    realloc(false, oldBreed);
  }

  @Override
  public Patch getPatchAtHeadingAndDistance(double delta, double distance)
      throws AgentException {
    double[] angles = right(delta);
    return ((Protractor3D) world.protractor()).getPatchAtHeadingPitchAndDistance
        (xcor, ycor, zcor,
            angles[0], angles[1], distance);
  }

  @Override
  public void turnRight(double delta) {
    double[] angles = right(delta);

    headingPitchAndRoll(angles[0], angles[1], angles[2]);
  }

  public double[] right(double delta) {
    delta = -delta;
    Vect[] v = Vect.toVectors(heading, pitch(), roll());

    double sinDelta = StrictMath.sin(StrictMath.toRadians(delta));
    double cosDelta = StrictMath.cos(StrictMath.toRadians(delta));
    if (StrictMath.abs(sinDelta) < org.nlogo.api.Constants.Infinitesimal()) {
      sinDelta = 0;
    }
    if (StrictMath.abs(cosDelta) < org.nlogo.api.Constants.Infinitesimal()) {
      cosDelta = 0;
    }

    Vect turnForward = new Vect(-sinDelta, cosDelta, 0);

    Vect turnRight = new Vect(cosDelta, sinDelta, 0);

    Vect orthogonal = v[1].cross(v[0]);

    Vect forward =
        Vect.axisTransformation(turnForward, v[1], v[0], orthogonal);
    Vect right =
        Vect.axisTransformation(turnRight, v[1], v[0], orthogonal);

    return Vect.toAngles(forward, right);
  }

  @Override
  public boolean hidden() {
    return ((Boolean) variables[VAR_HIDDEN3D]).booleanValue();
  }

  @Override
  public void hidden(boolean hidden) {
    variables[VAR_HIDDEN3D] = hidden ? Boolean.TRUE : Boolean.FALSE;
  }

  @Override
  public double size() {
    return ((Double) variables[VAR_SIZE3D]).doubleValue();
  }

  @Override
  public void size(double size) {
    variables[VAR_SIZE3D] = Double.valueOf(size);
  }

  @Override
  public double penSize() {
    return ((Double) variables[VAR_PENSIZE3D]).doubleValue();
  }

  @Override
  public void penSize(double penSize) {
    variables[VAR_PENSIZE3D] = Double.valueOf(penSize);
  }

  @Override
  public String penMode() {
    return (String) variables[VAR_PENMODE3D];
  }

  @Override
  public void penMode(String penMode) {
    variables[VAR_PENMODE3D] = penMode;
  }

  ///

  private void turtleMoved(double newX, double newY, double newZ, double oldX, double oldY, double oldZ) {
    ((TieManager3D) world.tieManager).turtleMoved(this, newX, newY, newZ, oldX, oldY, oldZ);
  }

  private void turtleOrientationChanged(double newHeading, double newPitch, double newRoll,
                                        double oldHeading, double oldPitch, double oldRoll) {
    ((TieManager3D) world.tieManager).turtleOrientationChanged(this, newHeading, newPitch, newRoll,
        oldHeading, oldPitch, oldRoll);
  }

}
TOP

Related Classes of org.nlogo.agent.Turtle3D

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.