001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.wpilibj.smartdashboard;
006
007import edu.wpi.first.networktables.NetworkTable;
008import edu.wpi.first.networktables.NetworkTableEntry;
009import java.util.HashMap;
010import java.util.Map;
011
012/**
013 * Root Mechanism2d node.
014 *
015 * <p>A root is the anchor point of other nodes (such as ligaments).
016 *
017 * <p>Do not create objects of this class directly! Obtain instances from the {@link
018 * Mechanism2d#getRoot(String, double, double)} factory method.
019 *
020 * <p>Append other nodes by using {@link #append(MechanismObject2d)}.
021 */
022public final class MechanismRoot2d {
023  private final String m_name;
024  private NetworkTable m_table;
025  private final Map<String, MechanismObject2d> m_objects = new HashMap<>(1);
026  private double m_x;
027  private NetworkTableEntry m_xEntry;
028  private double m_y;
029  private NetworkTableEntry m_yEntry;
030
031  /**
032   * Package-private constructor for roots.
033   *
034   * @param name name
035   * @param x x coordinate of root (provide only when constructing a root node)
036   * @param y y coordinate of root (provide only when constructing a root node)
037   */
038  MechanismRoot2d(String name, double x, double y) {
039    m_name = name;
040    m_x = x;
041    m_y = y;
042  }
043
044  /**
045   * Append a Mechanism object that is based on this one.
046   *
047   * @param <T> The object type.
048   * @param object the object to add.
049   * @return the object given as a parameter, useful for variable assignments and call chaining.
050   * @throws UnsupportedOperationException if the object's name is already used - object names must
051   *     be unique.
052   */
053  public synchronized <T extends MechanismObject2d> T append(T object) {
054    if (m_objects.containsKey(object.getName())) {
055      throw new UnsupportedOperationException("Mechanism object names must be unique!");
056    }
057    m_objects.put(object.getName(), object);
058    if (m_table != null) {
059      object.update(m_table.getSubTable(object.getName()));
060    }
061    return object;
062  }
063
064  /**
065   * Set the root's position.
066   *
067   * @param x new x coordinate
068   * @param y new y coordinate
069   */
070  public synchronized void setPosition(double x, double y) {
071    m_x = x;
072    m_y = y;
073  }
074
075  synchronized void update(NetworkTable table) {
076    m_table = table;
077    m_xEntry = m_table.getEntry("x");
078    m_yEntry = m_table.getEntry("y");
079    flush();
080    for (MechanismObject2d obj : m_objects.values()) {
081      obj.update(m_table.getSubTable(obj.getName()));
082    }
083  }
084
085  public String getName() {
086    return m_name;
087  }
088
089  private void flush() {
090    if (m_xEntry != null) {
091      m_xEntry.setDouble(m_x);
092    }
093    if (m_yEntry != null) {
094      m_yEntry.setDouble(m_y);
095    }
096  }
097}