Package org.nlogo.agent

Source Code of org.nlogo.agent.Link

// (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.LogoException;
import org.nlogo.api.LogoList;

import java.util.Iterator;

public strictfp class Link
    extends Agent
    implements org.nlogo.api.Link {

  /// ends

  final Turtle end1;

  public Turtle end1() {
    return end1;
  }

  final Turtle end2;

  public Turtle end2() {
    return end2;
  }

  /// id

  @Override
  public Object agentKey() {
    return this;
  }

  /// variables

  public static final int VAR_END1 = AgentVariableNumbers.VAR_END1;
  public static final int VAR_END2 = AgentVariableNumbers.VAR_END2;
  public static final int VAR_COLOR = AgentVariableNumbers.VAR_LCOLOR;
  public static final int VAR_LABEL = AgentVariableNumbers.VAR_LLABEL;
  static final int VAR_LABELCOLOR = AgentVariableNumbers.VAR_LLABELCOLOR;
  static final int VAR_HIDDEN = AgentVariableNumbers.VAR_LHIDDEN;
  public static final int VAR_BREED = AgentVariableNumbers.VAR_LBREED;
  public static final int VAR_THICKNESS = AgentVariableNumbers.VAR_THICKNESS;
  public static final int VAR_SHAPE = AgentVariableNumbers.VAR_LSHAPE;
  public static final int VAR_TIEMODE = AgentVariableNumbers.VAR_TIEMODE;

  public int LAST_PREDEFINED_VAR = VAR_TIEMODE;
  public int NUMBER_PREDEFINED_VARS = LAST_PREDEFINED_VAR + 1;

  /// birth & death

  public static final Double DEFAULT_COLOR = Double.valueOf(5.0); // gray

  public Link(World world, Turtle end1, Turtle end2, int arraySize) {
    super(world);
    variables = new Object[arraySize];
    variables[VAR_END1] = end1;
    variables[VAR_END2] = end2;
    this.end1 = end1;
    this.end2 = end2;

    this.id = world.newLinkId();

    for (int i = 2; i < variables.length; i++) {
      variables[i] = World.ZERO;
    }
  }

  Link(World world, Turtle end1, Turtle end2, AgentSet breed) {
    super(world);
    variables = new Object[world.getVariablesArraySize(this, breed)];
    variables[VAR_COLOR] = Color.BoxedBlack();
    variables[VAR_END1] = end1;
    variables[VAR_END2] = end2;
    variables[VAR_LABEL] = "";
    variables[VAR_LABELCOLOR] = Color.BoxedWhite();
    variables[VAR_HIDDEN] = Boolean.FALSE;
    variables[VAR_THICKNESS] = World.ZERO;
    variables[VAR_SHAPE] = world.linkBreedShapes.breedShape(breed);
    variables[VAR_TIEMODE] = MODE_NONE;
    this.end1 = end1;
    this.end2 = end2;

    this.id = world.newLinkId();

    variables[VAR_BREED] = breed;
    world.links().add(this);

    if (breed != world.links()) {
      breed.add(this);
    }

    for (int i = LAST_PREDEFINED_VAR + 1; i < variables.length; i++) {
      variables[i] = World.ZERO;
    }
  }

  public void die() {
    if (id == -1) {
      return;
    }
    AgentSet breed = getBreed();
    world.links().remove(agentKey());
    if (breed != world.links()) {
      breed.remove(agentKey());
    }
    world.linkManager.cleanup(this);
    id = -1;
  }

  ///

  @Override
  Agent realloc(boolean compiling) {
    return realloc(compiling, null);
  }

  Agent realloc(boolean compiling, AgentSet oldBreed) {
    // first check if we recompiled and our breed disappeared!
    if (compiling && getBreed() != world.links() &&
        world.getLinkBreed(getBreed().printName()) == null) {
      return this;
    }

    // stage 0: get ready
    Object[] oldvars = variables;
    variables = new Object[world.getVariablesArraySize(this, getBreed())];
    int linksOwnSize = world.getVariablesArraySize((Link) null, world.links());

    // stage 1: use arraycopy to copy over as many variables as possible
    // (if compiling it's just the predefined ones, if not compiling it's links-own too!)
    int numberToCopyDirectly = compiling ? NUMBER_PREDEFINED_VARS : linksOwnSize;
    System.arraycopy(oldvars, 0, variables, 0, numberToCopyDirectly);

    // stage 2: shift the turtles-own variables into their new positions
    // (unless we already did turtles-own during stage 1)
    if (compiling) {
      for (int i = NUMBER_PREDEFINED_VARS; i < linksOwnSize; i++) {
        String name = world.linksOwnNameAt(i);
        int oldpos = world.oldLinksOwnIndexOf(name);
        if (oldpos == -1) {
          variables[i] = World.ZERO;
        } else {
          variables[i] = oldvars[oldpos];
          oldvars[oldpos] = null;
        }
      }
    }

    // stage 3: handle the BREED-own variables
    for (int i = linksOwnSize; i < variables.length; i++) {
      String name = world.linkBreedsOwnNameAt(getBreed(), i);
      int oldpos = compiling ? world.oldLinkBreedsOwnIndexOf(getBreed(), name)
          : world.linkBreedsOwnIndexOf(oldBreed, name);
      if (oldpos == -1) {
        variables[i] = World.ZERO;
      } else {
        variables[i] = oldvars[oldpos];
        oldvars[oldpos] = null;
      }
    }
    return null;
  }

  @Override
  public Object getVariable(int vn) {
    return getLinkVariable(vn);
  }

  public String variableName(int vn) {
    if (vn < world.program().linksOwn().size()) {
      return world.linksOwnNameAt(vn);
    } else {
      return world.linkBreedsOwnNameAt(getBreed(), vn);
    }
  }

  @Override
  public Object getTurtleOrLinkVariable(String varName) {
    return getLinkVariable(world.program().linksOwn().indexOf(varName));
  }

  @Override
  public void setVariable(int vn, Object value)
      throws AgentException {
    setLinkVariable(vn, value);
  }

  @Override
  public Object getObserverVariable(int vn) {
    return world.observer().getObserverVariable(vn);
  }

  @Override
  public Object getLinkVariable(int vn) {
    return variables[vn];
  }

  public double getLinkVariableDouble(int vn) {
    switch (vn) {
      case VAR_THICKNESS:
        return lineThickness();
      default:
        throw new IllegalArgumentException
            (vn + " is not a double variable");
    }
  }

  @Override
  public void setObserverVariable(int vn, Object value)
      throws AgentException, LogoException {
    world.observer().setObserverVariable(vn, value);
  }

  @Override
  public void setTurtleOrLinkVariable(String varName, Object value)
      throws AgentException {
    setLinkVariable(world.program().linksOwn().indexOf(varName), value);
  }

  @Override
  public void setLinkVariable(int vn, double value) {
    switch (vn) {
      case VAR_THICKNESS:
        lineThickness(Double.valueOf(value));
        break;
      default:
        throw new IllegalArgumentException
            (vn + " is not a double variable");
    }
  }

  @Override
  public void setLinkVariable(int vn, Object value)
      throws AgentException {
    if (vn > LAST_PREDEFINED_VAR) {
      variables[vn] = value;
    } else {
      switch (vn) {
        case VAR_COLOR:
          if (value instanceof Double) {
            colorDouble((Double) value);
          } else if (value instanceof LogoList) {
            color((LogoList) value);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitLinkVariables()[vn],
                Double.class, value);
          }
          break;
        case VAR_LABEL:
          label(value);
          break;
        case VAR_LABELCOLOR:
          if (value instanceof Double) {
            labelColor(((Double) value).doubleValue());
          } else if (value instanceof LogoList) {
            labelColor((LogoList) value);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitLinkVariables()[vn],
                Double.class, value);
          }
          break;
        case VAR_HIDDEN:
          if (value instanceof Boolean) {
            hidden(((Boolean) value).booleanValue());
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitLinkVariables()[vn],
                Boolean.class, value);
          }
          break;
        case VAR_BREED:
          if (value instanceof AgentSet) {
            AgentSet breed = (AgentSet) value;
            if (breed != world.links() && !world.isLinkBreed(breed)) {
              throw new AgentException(I18N.errorsJ().get("org.nlogo.agent.Link.cantSetBreedToNonLinkBreedAgentSet"));
            }
            if (world.getLink(end1.agentKey(), end2.agentKey(), breed) != null) {
              throw new AgentException("there is already a "
                  + world.getLinkBreedSingular(breed)
                  + " with endpoints "
                  + end1.toString() + " and " + end2.toString());
            }
            if (!world.linkManager.checkBreededCompatibility(breed == world.links())) {
              throw new AgentException
                  (I18N.errorsJ().get("org.nlogo.agent.Link.cantHaveBreededAndUnbreededLinks"));
            }
            setBreed(breed);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitLinkVariables()[vn],
                AgentSet.class, value);
          }
          break;
        case VAR_THICKNESS:
          if (value instanceof Double) {
            lineThickness((Double) value);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitLinkVariables()[vn],
                Double.class, value);
          }
          break;
        case VAR_SHAPE:
          if (value instanceof String) {
            String newShape = world.checkLinkShapeName((String) value);
            if (newShape == null) {
              throw new AgentException(I18N.errorsJ().getN("org.nlogo.agent.Agent.shapeUndefined", value));
            }
            shape(newShape);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitLinkVariables()[vn],
                String.class, value);
          }
          break;
        case VAR_TIEMODE:
          if (value instanceof String) {
            mode((String) value);
          } else {
            wrongTypeForVariable(AgentVariables.getImplicitLinkVariables()[vn],
                String.class, value);
          }
          break;
        case VAR_END1:
        case VAR_END2:
          throw new AgentException("you can't change a link's endpoints");
        default:
          break;
      }
    }
    world.notifyWatchers(this, vn, value);
  }

  @Override
  public Object getTurtleVariable(int vn)
      throws AgentException {
    throw new AgentException
        ("a link can't access a turtle variable without specifying which turtle");
  }

  @Override
  public Object getBreedVariable(String name)
      throws AgentException {
    throw new AgentException
        ("a link can't access a turtle variable without specifying which turtle");
  }

  @Override
  public Object getLinkBreedVariable(String name)
      throws AgentException {
    mustOwn(name);
    int vn = world.linkBreedsOwnIndexOf(getBreed(), name);
    return getLinkVariable(vn);
  }

  @Override
  public Object getPatchVariable(int vn)
      throws AgentException {
    throw new AgentException
        ("a link can't access a patch variable without specifying which patch");
  }

  @Override
  public void setTurtleVariable(int vn, Object value)
      throws AgentException {
    throw new AgentException
        ("a link can't set a turtle variable without specifying which turtle");
  }

  @Override
  public void setTurtleVariable(int vn, double value)
      throws AgentException {
    throw new AgentException
        ("a link can't set a turtle variable without specifying which turtle");
  }

  @Override
  public void setBreedVariable(String name, Object value)
      throws AgentException {
    throw new AgentException
        ("a link can't set a turtle variable without specifying which turtle");
  }

  public void setBreedVariable(int vn, double value)
      throws AgentException {
    throw new AgentException
        ("a link can't set a turtle variable without specifying which turtle");
  }

  @Override
  public void setLinkBreedVariable(String name, Object value)
      throws AgentException {
    mustOwn(name);
    int vn = world.linkBreedsOwnIndexOf(getBreed(), name);
    setLinkVariable(vn, value);
  }

  @Override
  public void setPatchVariable(int vn, Object value)
      throws AgentException {
    throw new AgentException
        ("a link can't set a patch variable without specifying which turtle");
  }

  @Override
  public void setPatchVariable(int vn, double value)
      throws AgentException {
    throw new AgentException
        ("a link can't set a patch variable without specifying which turtle");
  }

  void mustOwn(String name)
      throws AgentException {
    if (name != null && !world.linkBreedOwns(getBreed(), name)) {
      throw new AgentException(
          I18N.errorsJ().getN("org.nlogo.agent.Agent.breedDoesNotOwnVariable",getBreed().printName(), name));
    }
  }

  ///

  public double x1() {
    return end1.xcor();
  }

  public double y1() {
    return end1.ycor();
  }

  public double x2() {
    return world.topology.shortestPathX(end1.xcor(), end2.xcor());
  }

  public double y2() {
    return world.topology.shortestPathY(end1.ycor(), end2.ycor());
  }

  public double midpointX() {
    double x1 = x1();
    double x2 = x2();

    return Topology.wrap((x1 + x2) / 2, world._minPxcor - 0.5, world._maxPxcor + 0.5);
  }

  public double midpointY() {
    double y1 = y1();
    double y2 = y2();

    return Topology.wrap((y1 + y2) / 2, world._minPycor - 0.5, world._maxPycor + 0.5);
  }

  public double heading() {
    try {
      return world.protractor().towards(end1, end2, true);
    } catch (AgentException e) {
      return 0;
    }
  }

  public double lineThickness() {
    return ((Double) variables[VAR_THICKNESS]).doubleValue();
  }

  public void lineThickness(Double value) {
    variables[VAR_THICKNESS] = value;
  }

  public boolean isDirectedLink() {
    return ((AgentSet) variables[VAR_BREED]).isDirected();
  }

  public double linkDestinationSize() {
    return end2.size();
  }

  public double size() {
    return world.protractor().distance(end1, end2, true);
  }

  public String shape() {
    return (String) variables[VAR_SHAPE];
  }

  public void shape(String shape) {
    variables[VAR_SHAPE] = shape;
  }

  public static final String MODE_NONE = "none";
  public static final String MODE_FREE = "free";
  public static final String MODE_FIXED = "fixed";

  public String mode() {
    return (String) variables[VAR_TIEMODE];
  }

  public void mode(String mode) {
    world.tieManager.setTieMode(this, mode);
    variables[VAR_TIEMODE] = mode;
  }

  public boolean isTied() {
    return !variables[VAR_TIEMODE].equals(MODE_NONE);
  }

  public void untie() {
    mode(MODE_NONE);
  }

  public Object color() {
    return variables[VAR_COLOR];
  }

  public void colorDouble(Double boxedColor) {
    double c = boxedColor.doubleValue();
    if (c < 0 || c >= Color.MaxColor()) {
      c = Color.modulateDouble(c);
      boxedColor = Double.valueOf(c);
    }
    variables[VAR_COLOR] = boxedColor;
  }

  public void colorDoubleUnchecked(Double boxedColor) {
    variables[VAR_COLOR] = boxedColor;
  }

  public void color(LogoList rgb)
      throws AgentException {
    validRGBList(rgb, true);
    variables[VAR_COLOR] = rgb;
    if(rgb.size() > 3) {
      world.mayHavePartiallyTransparentObjects = true;
    }
  }

  public AgentSet bothEnds() {
    AgentSet bothEnds = new ArrayAgentSet(Turtle.class, 2, false, world);
    bothEnds.add(end1);
    bothEnds.add(end2);
    return bothEnds;
  }

  @Override
  public Patch getPatchAtOffsets(double dx, double dy)
      throws AgentException {
    throw new AgentException
        ("links can't access patches via relative coordinates");
  }

  public Object label() {
    return variables[VAR_LABEL];
  }

  public boolean hasLabel() {
    return !(label() instanceof String &&
        ((String) label()).length() == 0);
  }

  public String labelString() {
    return Dump.logoObject(variables[VAR_LABEL]);
  }

  public void label(Object label) {
    variables[VAR_LABEL] = label;
  }

  public boolean hidden() {
    return ((Boolean) variables[VAR_HIDDEN]).booleanValue();
  }

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

  public AgentSet getBreed() {
    return (AgentSet) variables[VAR_BREED];
  }

  public Object labelColor() {
    return variables[VAR_LABELCOLOR];
  }

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

  public void labelColor(LogoList rgb)
      throws AgentException {
    validRGBList(rgb, true);
    variables[VAR_LABELCOLOR] = rgb;
  }

  @Override
  public String toString() {
    return world.getLinkBreedSingular(getBreed()).toLowerCase() + " " +
        end1.id + " " + end2.id;
  }

  @Override
  public String classDisplayName() {
    return world.getLinkBreedSingular(getBreed()).toLowerCase();
  }

  @Override
  public Class<Link> getAgentClass() {
    return Link.class;
  }

  public static final int BIT = 8;

  @Override
  public int getAgentBit() {
    return BIT;
  }

  public void setBreed(AgentSet breed) {
    AgentSet oldBreed = null;
    if (variables[VAR_BREED] instanceof AgentSet) {
      oldBreed = (AgentSet) variables[VAR_BREED];
      if (breed == oldBreed) {
        return;
      }
      if (oldBreed != world.links()) {
        ((AgentSet) variables[VAR_BREED]).remove(agentKey());
      }
    }
    if (breed != world.links()) {
      breed.add(this);
    }
    variables[VAR_BREED] = breed;
    shape(world.linkBreedShapes.breedShape(breed));
    realloc(false, oldBreed);
  }

  // returns the index of the breed of this link, 0 means a generic link;
  // this is super kludge. is there a better way? -AZS 10/28/04, ST 7/21/07
  public int getBreedIndex() {
    AgentSet mybreed = getBreed();
    if (mybreed == world.links()) {
      return 0;
    }
    int j = 1;
    for (Iterator<Object> iter = world.program().linkBreeds().values().iterator(); iter.hasNext();) {
      if (mybreed == ((AgentSet) iter.next())) {
        return j;
      }
      j++;
    }
    return 0;
  }

  @Override
  public int compareTo(Agent a) {
    if (a == this) {
      return 0;
    }
    Link otherLink = (Link) a;
    if (end1.id < otherLink.end1.id) {
      return -1;
    }
    if (end1.id > otherLink.end1.id) {
      return 1;
    }
    if (end2.id < otherLink.end2.id) {
      return -1;
    }
    if (end2.id > otherLink.end2.id) {
      return 1;
    }
    if (getBreed() == otherLink.getBreed()) {
      return 0;
    }
    if (getBreed() == world.links()) {
      return -1;
    }
    if (otherLink.getBreed() == world.links()) {
      return 1;
    }
    // when all else fails
    // whichever breed was declared first comes first in the list.
    return world.compareLinkBreeds(getBreed(), otherLink.getBreed());
  }

  public int alpha() {
    return org.nlogo.api.Color.getColor(color()).getAlpha();
  }

}
TOP

Related Classes of org.nlogo.agent.Link

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.