Package cc.sketchchair.sketch

Source Code of cc.sketchchair.sketch.SketchSpline

/*******************************************************************************
* This is part of SketchChair, an open-source tool for designing your own furniture.
*     www.sketchchair.cc
*    
*     Copyright (C) 2012, Diatom Studio ltd.  Contact: hello@diatom.cc
*
*     This program is free software: you can redistribute it and/or modify
*     it under the terms of the GNU General Public License as published by
*     the Free Software Foundation, either version 3 of the License, or
*     (at your option) any later version.
*
*     This program is distributed in the hope that it will be useful,
*     but WITHOUT ANY WARRANTY; without even the implied warranty of
*     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*     GNU General Public License for more details.
*
*     You should have received a copy of the GNU General Public License
*     along with this program.  If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
//#IF JAVA
package cc.sketchchair.sketch;

import java.awt.geom.GeneralPath;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;

import cc.sketchchair.core.LOGGER;
import cc.sketchchair.core.UndoAction;
import cc.sketchchair.functions.functions;
import cc.sketchchair.geometry.SlicePlane;

import nu.xom.Attribute;
import nu.xom.Element;

import processing.core.PGraphics;

import toxi.geom.Vec2D;
import toxi.geom.Vec3D;

/**
* A SketchSpline is a SketchPath with a offset.
* @author gregsaul
*
*/
//#ENDIF JAVA

public class SketchSpline extends SketchShape {

  SketchPath path;
  private SketchPath centrePath;

  public static final int TYPE_LEG = 43;
  public static final int CAP_ROUND = 1;
  public static final int CAP_BUTT = 2;
  public static final int CAP_SQUARE = 3;
  public static final int CAP_PARRALEL = 4;
  public static final int CAP_LEG = 5;

  public static final int JOIN_BEVEL = 1;
  public static final int JOIN_MITER = 2;
  public static final int JOIN_ROUND = 3;
 
  public static int OFFSET_LEFT = 0;
  public static int OFFSET_RIGHT = 1;
  public static int OFFSET_BOTH = 2;
 

  int capType = CAP_ROUND;
  int joinType = JOIN_BEVEL;

  ArrayList<SketchPoint> outineLeft = new ArrayList<SketchPoint>();
  ArrayList<SketchPoint> outineRight = new ArrayList<SketchPoint>();

  private Map<Integer, SketchPoint> outlineOffset = new Hashtable<Integer, SketchPoint>();
  private Map<Integer, Float> centreOffset = new Hashtable<Integer, Float>();

  int id = 0;

  boolean selected = true;
  boolean autoSmooth = true;

  boolean isOptimized;
  float pointDist = 5;// SETTINGS_SKETCH.dist_between_points; // distance
            // between
            // points
  // on the optimized line
  private float offsetSize = 20;// SETTINGS_SKETCH.offset_size;
  //public float offsetSizeEnd = 1;

  SliceSlots slots = new SliceSlots();
  boolean slots_on_inside = true;

  int offsetType = 2;
  public boolean isBuilt = false;
  private Object getSelectedNodes;
  private boolean legClickedOn;
  private boolean cacheLength;
  private int cachedLength;



  public SketchSpline(Sketch parentSketch) {
    super(parentSketch);

    path = new SketchPath(getParentSketch());
    centrePath = new SketchPath(getParentSketch());
    this.id = getParentSketch().sketch_id++;
    this.setType(SketchShape.TYPE_SPLINE);
    path.editable = false;
    path.setClosed(true);
    this.path.setParentSketch(this.getParentSketch());

  }

  public SketchSpline(Sketch parentSketch, Element element) {
    super(parentSketch);
    setParentSketch(parentSketch);
    path = new SketchPath(getParentSketch());
    centrePath = new SketchPath(getParentSketch());

    // wrong type
    if (!element.getLocalName().equals("SketchSpline"))
      return;

    if (element.getAttributeValue("id") != null) {
      this.setId(Integer.valueOf(element.getAttributeValue("id")));
    }

    if (element.getAttributeValue("outlineId") != null) {
      this.path.setId(Integer.valueOf(element
          .getAttributeValue("outlineId")));
    }

    if (element.getAttributeValue("centreId") != null) {
      this.getCentrePath().setId(
          Integer.valueOf(element.getAttributeValue("centreId")));
    }

    if (element.getAttributeValue("offsetSize") != null) {
      this.setOffsetSize(Float.valueOf(element
          .getAttributeValue("offsetSize")));
    }

    if (element.getAttributeValue("splineType") != null) {
      this.setType(Integer.valueOf(element
          .getAttributeValue("splineType")));
    }

    if (element.getAttributeValue("endCap") != null) {
      this.setCap(Integer.valueOf(element.getAttributeValue("endCap")));
    }

    if (element.getAttributeValue("joinType") != null) {
      this.setJoinType(Integer.valueOf(element
          .getAttributeValue("joinType")));
    }

    //this is from a legacy version also add a cap style to say it's a leg
    if (this.getType() == 0) {
      if (element.getAttributeValue("offsetSizeEnd") != null) {
      this.getCentreOffset().put(1,
          Float.valueOf(element.getAttributeValue("offsetSizeEnd")));
      }
     
      this.capType = SketchSpline.CAP_LEG;
      this.setType(TYPE_LEG);
    }

    if (element.getAttributeValue("isConstructionLine") != null) {
      this.setIsContructionLine(true);
    }

    if (element.getAttributeValue("union") != null) {
      this.union = Integer.valueOf(element.getAttributeValue("union"));
    }

    // for(int i = element.getChildCount()-1 ; i >= 0 ; i--){
    for (int i = 0; i < element.getChildCount(); i++) {

      Element child = (Element) element.getChild(i);

      if (child != null && child.getLocalName().equals("SketchPoint"))
        getCentrePath().add(new SketchPoint(child));

      if (child != null
          && child.getLocalName().equals("SketchSplineCentrePath")) {
        // for(int j = child.getChildCount()-1 ; j >= 0 ; j--){
        for (int j = 0; j < child.getChildCount(); j++) {

          Element child2 = (Element) child.getChild(j);

          if (child2 != null
              && child2.getLocalName().equals("SketchPoint"))
            getCentrePath().add(new SketchPoint(child2));

        }

      }

      if (child != null
          && child.getLocalName().equals("SketchSplineOffsets")) {
        // for(int j = child.getChildCount()-1 ; j >= 0 ; j--){
        for (int j = 0; j < child.getChildCount(); j++) {

          Element child2 = (Element) child.getChild(j);
          if (child2 != null
              && child2.getLocalName().equals(
                  "SketchSplineOffset")) {

            if (child2.getAttributeValue("linked_id") != null
                && child2.getAttributeValue("x_offset") != null
                && child2.getAttributeValue("y_offset") != null) {
              int index = Integer.valueOf(child2
                  .getAttributeValue("linked_id"));
              float x_offset = Float.valueOf(child2
                  .getAttributeValue("x_offset"));
              float y_offset = Float.valueOf(child2
                  .getAttributeValue("y_offset"));

              outlineOffset.put(index, new SketchPoint(x_offset,
                  y_offset));
              // outineOffset.put(1, new Vec2D(1,1));

            }

          }
        }
      }

      if (child != null
          && child.getLocalName().equals("SketchSplinePathOffsets")) {

        // for(int j = child.getChildCount()-1 ; j >= 0 ; j--){
        for (int j = 0; j < child.getChildCount(); j++) {

          Element child2 = (Element) child.getChild(j);
          if (child2 != null
              && child2.getLocalName().equals(
                  "SketchSplinePathOffset")) {

            if (child2.getAttributeValue("linked_index") != null
                && child2.getAttributeValue("offset") != null) {
              int index = Integer.valueOf(child2
                  .getAttributeValue("linked_index"));
              float offset = Float.valueOf(child2
                  .getAttributeValue("offset"));

              this.getCentreOffset().put(index, offset);
              // outineOffset.put(1, new Vec2D(1,1));

            }

          }
        }
      }

    }
    this.setClosed(true);

    path.editable = false;
    path.setClosed(true);
  }

  public SketchSpline(Sketch parentSketch, int offsetType) {
    super(parentSketch);
    setParentSketch(parentSketch);

    path = new SketchPath(getParentSketch());
    centrePath = new SketchPath(getParentSketch());
    this.offsetType = offsetType;
    this.id = getParentSketch().sketch_id++;
    path.editable = false;
    path.setClosed(true);
    this.path.setParentSketch(this.getParentSketch());

  }

  public void add(SketchPoint newVec) {

    if (getCentrePath().size() < 2
        || this.getLast().distanceTo(newVec) > 10) {
      getCentrePath().add(newVec);

      if (SETTINGS_SKETCH.dynamic_offset)
        this.offset();

    }

  }

  void addDynamicOffset(Vec2D newVec) {

    if (getCentrePath().size() == 3)
      this.offset();

    if (getCentrePath().size() > 3) {

      float tempOffset = this.getOffsetSize();
      float lenCurVec = this.getLenTo(newVec);
      if (lenCurVec <= this.getOffsetSize()) {
        tempOffset = (getOffsetSize() * ((float) Math
            .sqrt(1 - ((1 - (lenCurVec / getOffsetSize())) * (1 - (lenCurVec / getOffsetSize()))))));
      } else {
        tempOffset = this.getOffsetSize();

      }

      if (this.offsetType == SketchSpline.OFFSET_LEFT) {
        this.outineLeft
            .add((SketchPoint) getPerp(
                (float) (Math.PI / 2),
                tempOffset,
                (Vec2D) getCentrePath().get(
                    getCentrePath().size() - 1),
                (Vec2D) getCentrePath().get(
                    getCentrePath().size() - 3)));
        this.outineRight.add((SketchPoint) newVec);
      }

      if (this.offsetType == SketchSpline.OFFSET_RIGHT) {
        this.outineLeft.add((SketchPoint) newVec);
        this.outineRight
            .add((SketchPoint) getPerp(
                (float) (-Math.PI / 2),
                tempOffset,
                (Vec2D) getCentrePath().get(
                    getCentrePath().size() - 1),
                (Vec2D) getCentrePath().get(
                    getCentrePath().size() - 3)));
      }

      if (this.offsetType == SketchSpline.OFFSET_BOTH) {
        this.outineLeft
            .add((SketchPoint) getPerp(
                (float) (Math.PI / 2),
                tempOffset,
                (Vec2D) getCentrePath().get(
                    getCentrePath().size() - 1),
                (Vec2D) getCentrePath().get(
                    getCentrePath().size() - 3)));
        this.outineRight
            .add((SketchPoint) getPerp(
                (float) (-Math.PI / 2),
                tempOffset,
                (Vec2D) getCentrePath().get(
                    getCentrePath().size() - 1),
                (Vec2D) getCentrePath().get(
                    getCentrePath().size() - 3)));
      }

    }

  }

  void addOffset(SketchPoint newVec) {
    toxi.geom.Vec3D v = new toxi.geom.Vec3D(newVec.x, newVec.y, 0);
    this.outineLeft.add((SketchPoint) newVec);
  }

  private void applyOutlineOffset() {
    // this.optimize();
    if (getCentrePath().size() == 2)
      this.path.editable = true;
    else
      this.path.editable = false;

    if (getCentrePath().size() > 2)
      return;

    for (int i = 0; i < getCentrePath().size(); i++) {
      SketchPoint curVec = (SketchPoint) getCentrePath().get(i);

      if (this.outlineOffset.containsKey(i) && this.path.size() >= i) {
        if (this.path.size() > i) {
          Vec2D outline = (Vec2D) this.path.get(i);
          Vec2D offset = this.outlineOffset.get(i);
          outline.x = curVec.sub(offset).x;
          outline.y = curVec.sub(offset).y;
        }
        // this.outineLeft.set(i, outline);
      }

    }

    for (int i = 0; i < getCentrePath().size(); i++) {
      Vec2D curVec = (Vec2D) getCentrePath().get(i);
      int i2 = ((getCentrePath().size() * 2) - i - 1);
      if (this.outlineOffset.containsKey(i2) && this.path.size() >= i2) {
        if (this.path.size() >= i2) {
          Vec2D outline = (Vec2D) this.path.get(i2);
          Vec2D offset = this.outlineOffset.get(i2);
          outline.x = curVec.sub(offset).x;
          outline.y = curVec.sub(offset).y;
        }
        // this.outineLeft.set(i, outline);
      }

    }

  }

  public void build() {
    this.offset();
  }

  private void buildPath() {

    this.path.reset();

    for (int i = 0; i < this.getCombinedSize(); i++) {
      SketchPoint curVec = (SketchPoint) this.getCombined(i);
      this.path.add(curVec);
    }
  }

  public SketchSpline clone() {
    SketchSpline newSpline = new SketchSpline(getParentSketch());
    newSpline.setType(this.getType());
    newSpline.setCap(this.getCap());
    newSpline.setJoinType(this.getJoinType());

    if (this.getCentrePath() != null)
      newSpline.setCentrePath(this.getCentrePath().clone());

    for (int i = 0; i < this.outineLeft.size(); i++) {
      Vec2D curVec = this.outineLeft.get(i);
      newSpline.outineLeft.add(new SketchPoint(curVec.x, curVec.y));
    }

    for (int i = 0; i < this.outineRight.size(); i++) {
      Vec2D curVec = this.outineRight.get(i);
      newSpline.outineRight.add(new SketchPoint(curVec.x, curVec.y));
    }

    for (int i = 0; i < this.getCentrePath().size(); i++) {
      if (this.getCentreOffset().get(i) != null)
        newSpline.getCentreOffset().put(i,
            this.getCentreOffset().get(i));
    }

    newSpline.slots = this.slots.clone();

    newSpline.setOffsetSize(this.getOffsetSize());
    newSpline.path = this.path.clone();
    newSpline.isBuilt = this.isBuilt;
    newSpline.offsetType = this.offsetType;
    newSpline.path.editable = this.path.editable;
    newSpline.setClosed(this.getClosed());
    //newSpline.offset();
    return newSpline;

  }

  public SketchSpline copy(Sketch parentSketch) {
    SketchSpline newSketchSpline = new SketchSpline(parentSketch);

    newSketchSpline.setId(this.getId());
    newSketchSpline.path.setId(this.path.getId());
    newSketchSpline.getCentrePath().setId(this.getCentrePath().getId());

    newSketchSpline.offsetSize = this.offsetSize;
    newSketchSpline.setType(this.getType());
    newSketchSpline.setCap(this.getCap());
    newSketchSpline.setJoinType(this.getJoinType());

    for (int i = 0; i < getCentrePath().size(); i++) {
      SketchPoint skPoint = (SketchPoint) getCentrePath().get(i);
      SketchPoint skPointCopy = skPoint.clone();
      newSketchSpline.getCentrePath().add(skPointCopy);
      if (this.getCentreOffset().containsKey(i)) {
        newSketchSpline.getCentreOffset().put(i,
            getCentreOffset().get(i));
      }

    }

    newSketchSpline.setClosed(this.getClosed());

    return newSketchSpline;
  }

  public int countSelectedNodes() {
    return getSelectedNodes().size() + this.path.countSelectedNodes();
  }

  public void destroy() {
    this.setDestroy(true);

    if (this.getCentrePath() != null)
      this.getCentrePath().setDestroy(true);
    //this.setCentrePath(null);
  }

  public void flipHorizontal(toxi.geom.Vec3D centre) {
    this.getCentrePath().flipHorizontal(centre);
    this.path.flipHorizontal(centre);
  }

  public int getCap() {
    return capType;
  }


  public Map<Integer, Float> getCentreOffset() {
    return centreOffset;
  }

  public Vec2D getCentreOfMass() {
    long x = 0;
    long y = 0;

    for (int i = 0; i < this.getCombinedSize(); i++) {
      Vec2D v = (Vec2D) this.getCombined(i);
      x += v.x;
      y += v.y;
    }
    return new Vec2D(x / this.getCombinedSize(), y / this.getCombinedSize());
  }

  public SketchPath getCentrePath() {
    return this.centrePath;
  }

  public float getClosestPercent(float mouseX, float mouseY) {
    return this.getCentrePath().getClosestPercent(mouseX, mouseY);
    //return this.path.getClosestPercent(mouseX, mouseY);
  }

  public SketchPoint getClosestPoint(SketchPoint pointOnPlan) {
    return this.getCentrePath().getClosestPoint(pointOnPlan);
  }

  public SketchPoint getClosestPoint(Vec2D pointOnPlan) {
    return this.getCentrePath().getClosestPoint(pointOnPlan);
  }

  public Vec2D getClosestPointAlongPath(float x, float y) {
    Vec2D mPos = new Vec2D(x, y);
    Vec2D centreP = this.getCentrePath().getClosestPointAlongPath(x, y);
    Vec2D outlineP = this.getPath().getClosestPointAlongPath(x, y);

    if (mPos == null || centreP == null || outlineP == null)
      return null;

    if (centreP.distanceTo(mPos) < outlineP.distanceTo(mPos))
      return centreP;
    else
      return outlineP;

  }

  int getColor(int id) {
    return -(id + 2);
  }

  public SketchPoint getCombined(int i) {
    if (i < this.outineRight.size())
      return this.outineRight.get(i);
    else
      return this.outineLeft.get(this.outineLeft.size()
          - (i - this.outineRight.size()) - 1);
  }

  public int getCombinedSize() {
    return this.outineRight.size() + this.outineLeft.size();
  }

  private float getDistBetween(Vec2D first, Vec2D second) {
    float length = 0;

    if (first == second)
      return length;

    Vec2D startVec = null;

    for (int i = 0; i < getCentrePath().size() - 1; i++) {
      Vec2D curVec = (Vec2D) getCentrePath().get(i);
      Vec2D nextVec = (Vec2D) getCentrePath().get(i + 1);

      if (startVec == null && (curVec == first || curVec == second))
        startVec = curVec;

      if (startVec != null)
        length += curVec.distanceTo(nextVec);

      if (startVec != null && (nextVec == first || nextVec == second))
        return length;

    }
    return length;
  }

  public Vec2D getFirst() {

    if (getCentrePath().size() > 0)
      return (Vec2D) getCentrePath().get(0);
    else
      return null;
  }

  private int getIndex(Vec2D startVec) {
    for (int i = 0; i < getCentrePath().size(); i++) {
      Vec2D vec = (Vec2D) getCentrePath().get(i);
      if (startVec == vec)
        return i;
    }

    return -1;
  }

  private int getJoinType() {
    return this.joinType;
  }

  public SketchPoint getLast() {

    if (getCentrePath().size() > 0)
      return (SketchPoint) getCentrePath()
          .get(getCentrePath().size() - 1);
    else
      return null;
  }

  public float getlength() {
    float length = 0;

    for (int i = 0; i < getCentrePath().size() - 1; i++) {
      Vec2D curVec = (Vec2D) getCentrePath().get(i);
      Vec2D nextVec = (Vec2D) getCentrePath().get(i + 1);

      if (curVec != null && nextVec != null)
        length += curVec.distanceTo(nextVec);
    }

    return length;
  }

  public int getLength() {
    return getCentrePath().size();
  }

  public float getLenTo(Vec2D curVecC) {
    float length = 0;

    if (curVecC == null)
      return -1;

    for (int i = 0; i < getCentrePath().size() - 1; i++) {
      Vec2D curVec = (Vec2D) getCentrePath().get(i);
      Vec2D nextVec = (Vec2D) getCentrePath().get(i + 1);

      if (curVecC != nextVec && curVecC != curVec && nextVec != null)
        length += curVec.distanceTo(nextVec);
      else
        return length;

    }
    return -1;

  }

  private Vec2D getNearestVec(Vec2D selectedNode) {
    Vec2D foundVec = null;
    float dist = 0;

    for (int i = 0; i < getCentrePath().size(); i++) {
      Vec2D vec = (Vec2D) getCentrePath().get(i);
      if (vec.distanceTo(selectedNode) < dist || foundVec == null) {
        dist = vec.distanceTo(selectedNode);
        foundVec = vec;
      }
    }

    return foundVec;
  }

  private int getNearestVecIndex(Vec2D selectedNode) {
    int index = -1;
    float dist = 0;

    for (int i = 0; i < getCentrePath().size(); i++) {
      Vec2D vec = (Vec2D) getCentrePath().get(i);
      if (vec.distanceTo(selectedNode) < dist || index == -1) {
        dist = vec.distanceTo(selectedNode);
        index = i;
      }
    }

    return index;
  }

  /**
   * @return the offsetSize
   */
  public float getOffsetSize() {
    return offsetSize;
  }

  public float getOffsetSize(float percent) {

    int startNodeIndex = this.getCentrePath().getPosIndex(percent);
    float startNodePercent = this.getCentrePath().getPercent(
        this.getCentrePath().get(startNodeIndex));
    float endNodePercent = this.getCentrePath().getPercent(
        this.getCentrePath().get(startNodeIndex + 1));
    float currentSegPercent = (endNodePercent - startNodePercent);
    float betweenPercent = (percent - startNodePercent) / currentSegPercent;

    float thisOffset = this.getOffsetSize();
    float nextOffset = this.getOffsetSize();

    if (this.getCentreOffset().containsKey(startNodeIndex))
      thisOffset = getCentreOffset().get(startNodeIndex);

    if (this.getCentreOffset().containsKey(startNodeIndex + 1))
      nextOffset = getCentreOffset().get(startNodeIndex + 1);

    return (thisOffset * (1 - betweenPercent))
        + (nextOffset * (betweenPercent));

  }

  public GeneralPath getOutlineGeneralPath() {

    return this.path.getOutlineGeneralPath();

  }

  public SketchShape getOverShape(float x, float y) {
    Vec2D closePoint = this.path.getClosestPointAlongPath(x, y);
    Vec2D closePointCentre = this.getCentrePath().getClosestPointAlongPath(
        x, y);

    float distToClosePoint = 0;
    float distToClosePointCentre = 0;

    if (closePoint != null)
      distToClosePoint = closePoint.distanceTo(new Vec2D(x, y));

    if (closePointCentre != null)
      distToClosePointCentre = closePointCentre
          .distanceTo(new Vec2D(x, y));

    if (closePoint != null && (distToClosePoint <= distToClosePointCentre)
        && distToClosePoint < SETTINGS_SKETCH.SELECT_EDGE_DIST) {
      this.path.lastMouseOverVec = closePoint;
      this.path.lastMouseOverPercent = this.path.getClosestPercent(x, y);
      return this.path;
    }

    closePoint = this.getCentrePath().getClosestPointAlongPath(x, y);

    if (closePoint != null && (distToClosePointCentre < distToClosePoint)
        && distToClosePointCentre < SETTINGS_SKETCH.SELECT_EDGE_DIST) {
      this.lastMouseOverVec = closePoint;
      this.lastMouseOverPercent = this.getCentrePath().getClosestPercent(
          x, y);
      return this;
    }

    /*
     * Vec2D closePointC = this.centrePath.getClosestPointAlongPath(x,y);
     * if(closePointC != null && closePointC.distanceTo(new Vec2D(x,y)) <
     * SETTINGS_SKETCH.SELECT_EDGE_DIST){ this.centrePath.lastMouseOverVec =
     * closePointC; this.centrePath.lastMouseOverPercent =
     * this.centrePath.getClosestPercent(x,y); return this.centrePath; }
     */

    return null;
  }

  public SketchPath getPath() {
    return this.path;

  }

  SketchPoint getPerp(float angle, float offsetDelta, Vec2D vec1, Vec2D vec2) {

    Vec2D curVec2 = vec1;// (Vec2D) centrePath.get(centrePath.size() - 1);
    Vec2D prevVec = vec2;// (Vec2D) centrePath.get(centrePath.size() - 3);
    Vec2D curAnNext = curVec2.sub(prevVec);
    curAnNext.normalize();
    Vec2D newAn = curAnNext.getRotated(angle);
    newAn.normalize();
    newAn.scaleSelf(offsetDelta);
    newAn.addSelf(curVec2);
    return new SketchPoint(newAn.x, newAn.y);

  }

  public Vec2D getPerpendicular(float percent) {
    return this.getCentrePath().getPerpendicular(percent);


  }

  public Vec2D getPos(float percent) {
    return getCentrePath().getPos(percent);
   
  }

  protected ArrayList<Object> getSelectedNodes() {
    return this.getCentrePath().getSelectedNodes();
  }

  public SketchPoint getSketchPointpickBuffer(int col) {
    // TODO Auto-generated method stub
    return null;
  }

  public SketchPoint getVec2DpickBuffer(int col) {
    for (int i = 0; i < getCentrePath().size(); i++) {
      SketchPoint curVec = (SketchPoint) getCentrePath().get(i);
      if (col == getColor(i + (this.id * 100)))
        return curVec;
    }

    for (int i = 0; i < this.path.size(); i++) {
      SketchPoint curVec = (SketchPoint) this.path.get(i);
   
      if (col == getColor(getCentrePath().size() + i + (this.id * 100))) {
        return curVec;
      }
    }

    return null;
  }

  public void insertPoint(SketchPoint closestPoint) {
    this.getCentrePath().insertPoint(closestPoint);
  }

  public boolean isPointInside(Vec2D p) {
    return this.path.isPointInside(p);
  }

  public void mouseDragged(float mouseX, float mouseY) {

    Vec2D pointOnPlane = new Vec2D(mouseX, mouseY);

    if (this.path.editable)
      this.path.mouseDragged(mouseX, mouseY);

    if (getParentSketch().getSketchTools().getCurrentTool() == SketchTools.SELECT_TOOL) {
      for (int i = 0; i < this.getSelectedNodes().size(); i++) {
        Vec2D v = (Vec2D) this.getSelectedNodes().get(i);

        if (this.getType() == SketchShape.TYPE_SPLINE)
          this.movePointFalloff(v, pointOnPlane);

        if (this.getType() == SketchShape.OFFSET_SPLINE)
          this.movePoint(v, pointOnPlane);

        if (getCentrePath().size() == 2)
          this.legClickedOn = true;

      }

      for (int i = 0; i < this.getSelectedNodes().size(); i++) {
        Object v = (Object) this.getSelectedNodes().get(i);

        if (v instanceof SketchPoint) {
          this.movePoint((SketchPoint) v, pointOnPlane);
        } else if (v instanceof Vec2D)
          this.movePoint((Vec2D) v, pointOnPlane);

        //TODO: this could be a smooth tool!
        //if (getCentrePath().size() != 2)
        //  this.optimize();

      }

    }

    this.getCentrePath().mouseDragged(mouseX, mouseY);

    if (this.getSelectedNodes().size() > 0
        || this.getCentrePath().getSelectedNodes().size() > 0)
      this.offset();

  }

  public void mouseReleased(float mouseX, float mouseY) {
    this.optimize();
    this.legClickedOn = false;

    //remove stray points
    if(this.centrePath.size() <= 1){
      this.destroy();
    LOGGER.debug("destroy shape not enough points")
    }
  }

  public void movePoint(SketchPoint selectedVec, Vec2D planePoint) {
    // TODO Auto-generated method stub
    if (selectedVec.containsBezier()) {

      //Vec2D delta = selectedVec.sub(planePoint);
      //System.out.println(pointOnPlane);
      //LOGGER.info("here 1 "+ planePoint);
      //LOGGER.info("here 2 "+ selectedVec);

      //selectedVec.controlPoint1.subSelf(delta);
      //selectedVec.controlPoint2.subSelf(delta);

    }

    //selectedVec.x = planePoint.x;
    //selectedVec.y = planePoint.y;

  }

  public void movePoint(Vec2D v, Vec2D planePoint) {

    //if (getCentrePath().size() > 2)
    //return;

    //v.set(planePoint);

    /*
    // System.out.print("here");
    if (getCentrePath().contains(selectedVec)) {
      selectedVec.x = planePoint.x;
      selectedVec.y = planePoint.y;

      this.offset();
    }

    if (this.path.contains(selectedVec)) {
      int index = this.path.indexOf(selectedVec);
      Vec2D outlineP = (Vec2D) this.path.get(index);
      Vec2D centreP = null;

      if (index < getCentrePath().size())
        centreP = (Vec2D) getCentrePath().get(index);
      else
        centreP = (Vec2D) getCentrePath().get(
            (getCentrePath().size() * 2) - index - 1);

      if (!outineOffset.containsKey(index))
        outineOffset.put(index, new Vec2D());

      Vec2D offset = outineOffset.get(index);

      offset.x = centreP.x - planePoint.x;
      offset.y = centreP.y - planePoint.y;
      applyOutlineOffset();

    }
    */

  }

  private void movePointFalloff(Vec2D selectVec, Vec2D pointOnPlane) {

    if (this.getCentrePath().size() <= 2)
      return;

    Vec2D diff = pointOnPlane.sub(selectVec);
    Vec2D startVec = null;
    Vec2D endVec = null;
    Vec2D lastVec = null;

    int pointIndex = this.getIndex(selectVec);

    if (pointIndex == 0) {
      // if we have one of the end points just drag them
      selectVec.set(pointOnPlane);

      if (startVec == null)
        startVec = selectVec;

      if (startVec != null && getCentrePath().size() > 3)
        endVec = (Vec2D) getCentrePath().get(3);
      else
        endVec = (Vec2D) getCentrePath()
            .get(getCentrePath().size() - 1);

    } else if (pointIndex == getCentrePath().size() - 1) {

      // if we have one of the end point just drag them
      selectVec.set(pointOnPlane);

      if (getCentrePath().size() > 1) {
        Vec2D v = (Vec2D) getCentrePath().get(
            getCentrePath().size() - 2);

        v.x += diff.scale(.2f).x;
        v.y += diff.scale(.2f).y;
      }

      if (startVec == null && getCentrePath().size() > 3)
        startVec = (Vec2D) getCentrePath().get(
            getCentrePath().size() - 3);
      else
        startVec = (Vec2D) getCentrePath().get(0);

      if (startVec != null)
        endVec = selectVec;

    } else {

      for (int i = 0; i < getCentrePath().size(); i++) {
        Vec2D v = (Vec2D) getCentrePath().get(i);

        // float dist = v.distanceTo(selectVec);

        float dist = this.getDistBetween(v, selectVec);
        float fieldDia = SETTINGS_SKETCH.splineMoveFalloff * (1 / getParentSketch().getZOOM());
        float delta = (fieldDia - dist) / fieldDia;
       
        // if (delta < 0)
        // delta = 0;
        // System.out.println(dist);
       
        if (dist < fieldDia) {

          float scale = (float) Math.sin(((Math.PI / 2) * delta));
          Vec2D shapedDiff = diff.scale(scale);

          /*
          if (i != 0 && i != getCentrePath().size() - 1
              || delta > .99f) {
              */
            // if(true){
            v.x += shapedDiff.x;
            v.y += shapedDiff.y;

            // System.out.println("d"+dist);

            if (startVec == null)
              startVec = v;

            if (startVec != null)
              endVec = v;

          //}

        }

      }
    }
 
    optimizeRange(startVec, endVec);
    // optimize();
  }

  /**
   * Apply outline offset
   *
   */

  public void offset() {
    if (getCentrePath().size() < 2)
      return;

    float offsetSize1 = 0;
    float offsetSize2 = 0;

    if (this.getCentreOffset().get(1) != null)
      offsetSize1 = this.getCentreOffset().get(1);

    //if (offsetSize1 == 0)
    //SketchSpline.  offsetSize1 = this.offsetSizeEnd;

    if (this.getCentreOffset().get(0) != null)
      offsetSize2 = this.getCentreOffset().get(0);

    if (offsetSize2 == 0)
      offsetSize2 = this.getOffsetSize();

   
    //if (getCentrePath().size() < 3 && this.getType() != SketchSpline.OFFSET_SPLINE)
    //  return;

    this.outineLeft = new ArrayList<SketchPoint>();
    this.outineRight = new ArrayList<SketchPoint>();

    float tempOffset = getOffsetSize();
    float tempOffsetNext = tempOffset;

    /**
     * OFFSET the path
     *
     * |:| :| |:
     * |:| :| |:
     * |:| :| |:
     *
     */
    //Go through each point on the path and work out the angle of the line to and from it.
    for (int i = 0; i < getCentrePath().size(); i++) {
      Vec2D curveNormal1 = null;
      Vec2D curveNormal2 = null;
     
      Vec2D curveNormalPrev1 = null;
      Vec2D curveNormalPrev2 = null;

      Vec2D prevVec = null;
      Vec2D nextVec = null;
      Vec2D curVec = null;
      SketchPoint curPoint = null;
      SketchPoint nextPoint = null;
      SketchPoint prevPoint = null;

      curVec = (Vec2D) getCentrePath().get(i);
      curPoint = getCentrePath().get(i);

      if (curVec == null)
        break;

      if (i == 0 && i < getCentrePath().size()) {
        nextVec = (Vec2D) getCentrePath().get(i + 1);
        nextPoint = getCentrePath().get(i + 1);
        curveNormal2 = (Vec2D) nextVec.sub(curVec).normalize();
      } else if (i > getCentrePath().size() - 2) {
        prevVec = (Vec2D) getCentrePath().get(i - 1);
        prevPoint = getCentrePath().get(i - 1);
        curveNormal1 = curVec.sub((Vec2D) prevVec).normalize();
      } else {

        prevVec = (Vec2D) getCentrePath().get(i - 1);
        nextVec = (Vec2D) getCentrePath().get(i + 1);
        nextPoint = getCentrePath().get(i + 1);
        prevPoint = getCentrePath().get(i - 1);

        if (nextVec == null)
          nextVec = curVec;

        Vec2D curAnPrev = curVec.sub(prevVec);
        Vec2D curAnNext = nextVec.sub(curVec);

        curAnPrev.normalize();
        curAnNext.normalize();

        // curAnPrev.addSelf(curAnNext);

        // curAnPrev.scaleSelf(0.5f);
        curveNormal1 = curAnPrev;
        curveNormal2 = curAnNext;

      }
     

      tempOffset = this.getOffsetSize();
      tempOffsetNext = this.getOffsetSize();

      if (getCentreOffset().containsKey(i))
        tempOffset = this.getCentreOffset().get(i);

      if (nextPoint != null && getCentreOffset().containsKey(i + 1)) {
        tempOffsetNext = this.getCentreOffset().get(i + 1);
      }

      if (prevPoint != null && prevPoint.controlPoint2 != null
          && !prevPoint.controlPoint2.equals(prevPoint)) {
        prevVec = prevPoint.controlPoint2;
        curveNormal1 = curVec.sub((Vec2D) prevVec).normalize();
      }

      if (nextPoint != null && nextPoint.controlPoint1 != null
          && !nextPoint.controlPoint1.equals(nextPoint)) {
        nextVec = nextPoint.controlPoint1;
        curveNormal2 = nextVec.sub((Vec2D) curVec).normalize();
      }

      //Are we a bezier
      if (curPoint.controlPoint1 != null
          && !curPoint.controlPoint1.equals(curPoint)
          && prevVec != null) {
        prevVec = curPoint.controlPoint1;
        curveNormal1 = curVec.sub((Vec2D) prevVec).normalize();
      }

      if (curPoint.controlPoint2 != null
          && !curPoint.controlPoint2.equals(curPoint)
          && nextVec != null) {
        nextVec = curPoint.controlPoint2;
        curveNormal2 = (Vec2D) nextVec.sub(curVec).normalize();
      }

      /*
       * Now we Have these angles go though and work out the offset points
       */
      Vec2D newAnLeft1 = null, newAnRight1 = null, newAnLeft2 = null, newAnRight2 = null;

if((curveNormal1 != null && curveNormal1.x == 0 && curveNormal1.y ==0))
  curveNormal1 = curveNormalPrev1;

if((curveNormal2 != null && curveNormal2.x == 0 && curveNormal2.y ==0))
  curveNormal2 = curveNormalPrev2;
 

curveNormalPrev1 = curveNormal1;
curveNormalPrev2 = curveNormal2;
 
      if (curveNormal1 != null) {
        newAnLeft1 = (Vec2D) curveNormal1
            .getRotated((float) (Math.PI / 2));
        newAnLeft1.normalize();
        newAnLeft1.scaleSelf(tempOffset);
        newAnLeft1.addSelf(curVec);

        newAnRight1 = (Vec2D) curveNormal1
            .getRotated((float) (Math.PI / 2));
        newAnRight1.normalize();
        newAnRight1.scaleSelf(-tempOffset);
        newAnRight1.addSelf(curVec);
      }

      if (curveNormal2 != null ) {
        newAnLeft2 = (Vec2D) curveNormal2
            .getRotated((float) (Math.PI / 2));
        newAnLeft2.normalize();
        newAnLeft2.scaleSelf(tempOffset);
        newAnLeft2.addSelf(curVec);

        newAnRight2 = (Vec2D) curveNormal2
            .getRotated((float) (Math.PI / 2));
        newAnRight2.normalize();
        newAnRight2.scaleSelf(-tempOffset);
        newAnRight2.addSelf(curVec);
      }
     



      /*
       * If join is set to MITER then move points to form a point
       */

      if (newAnLeft1 != null && newAnLeft2 != null
          && this.joinType == SketchSpline.JOIN_MITER) {
        float projectLen = 1000;
        Vec2D backLine = newAnLeft1.add(curveNormal1.scale(projectLen));
        Vec2D fowardLine = newAnLeft2.sub(curveNormal2
            .scale(projectLen));

        if (functions.intersect(newAnLeft1.x, newAnLeft1.y, backLine.x,
            backLine.y, newAnLeft2.x, newAnLeft2.y, fowardLine.x,
            fowardLine.y) == functions.DO_INTERSECT) {
          newAnLeft1.x = functions.x;
          newAnLeft1.y = functions.y;
          newAnLeft2.x = functions.x;
          newAnLeft2.y = functions.y;

        }

      }

      if (newAnRight1 != null && newAnRight2 != null
          && this.joinType == SketchSpline.JOIN_MITER) {
        float projectLen = 1000;
        Vec2D backLine = newAnRight1
            .add(curveNormal1.scale(projectLen));
        Vec2D fowardLine = newAnRight2.sub(curveNormal2
            .scale(projectLen));

        if (functions.intersect(newAnRight1.x, newAnRight1.y,
            backLine.x, backLine.y, newAnRight2.x, newAnRight2.y,
            fowardLine.x, fowardLine.y) == functions.DO_INTERSECT) {
          newAnRight1.x = functions.x;
          newAnRight1.y = functions.y;
          newAnRight2.x = functions.x;
          newAnRight2.y = functions.y;

        }
      }

     

      /*
       * Modify Offset points to account for offset dir.
       */

      SketchPoint outlinePointLeft1 = null, outlinePointRight1 = null, outlinePointLeft2 = null, outlinePointRight2 = null;

      if (this.offsetType == SketchSpline.OFFSET_LEFT) {
        if (newAnLeft1 != null) {
          outlinePointLeft1 = new SketchPoint(newAnLeft1);
          outlinePointRight1 = new SketchPoint(curVec);
        }

        if (newAnLeft2 != null) {
          outlinePointLeft2 = new SketchPoint(newAnLeft2);
          outlinePointRight2 = new SketchPoint(curVec);
        }

      }

      if (this.offsetType == SketchSpline.OFFSET_RIGHT) {
        if (newAnRight1 != null) {
          outlinePointLeft1 = new SketchPoint(curVec);
          outlinePointRight1 = new SketchPoint(newAnRight1);
        }

        if (newAnRight2 != null) {
          outlinePointLeft2 = new SketchPoint(curVec);
          outlinePointRight2 = new SketchPoint(newAnRight2);
        }

      }

      if (this.offsetType == SketchSpline.OFFSET_BOTH) {
        if (newAnLeft1 != null && newAnRight1 != null) {
          outlinePointLeft1 = new SketchPoint(newAnLeft1);
          outlinePointRight1 = new SketchPoint(newAnRight1);
        }

        if (newAnLeft2 != null && newAnRight2 != null) {
          outlinePointLeft2 = new SketchPoint(newAnLeft2);
          outlinePointRight2 = new SketchPoint(newAnRight2);
        }
      }

     

     
      /*
       * If Join is set to JOIN_ROUND then add beziers to joins and move acute angled points to allow interior curves to be added
       * Should we more outside points to make a more constant curve?
       */
      if (this.joinType == SketchSpline.JOIN_ROUND) {

        if (outlinePointLeft1 != null && outlinePointLeft2 != null
            && outlinePointLeft1.distanceTo(outlinePointLeft2) == 0) {
          float pushDist = outlinePointRight1
              .distanceTo(outlinePointRight2) / 2;

          if (prevVec != null
              && curVec.distanceTo(prevVec) < pushDist)
            pushDist = curVec.distanceTo(prevVec);

          if (nextVec != null
              && curVec.distanceTo(nextVec) < pushDist)
            pushDist = curVec.distanceTo(nextVec);

          outlinePointLeft1.subSelf(curveNormal1.scale(pushDist));
          outlinePointLeft2.addSelf(curveNormal2.scale(pushDist));

        }

        if (outlinePointRight1 != null
            && outlinePointRight2 != null
            && outlinePointRight1.distanceTo(outlinePointRight2) == 0) {
          float pushDist = outlinePointLeft1
              .distanceTo(outlinePointLeft2) / 2;

          if (prevVec != null
              && curVec.distanceTo(prevVec) < pushDist)
            pushDist = curVec.distanceTo(prevVec);

          if (nextVec != null
              && curVec.distanceTo(nextVec) < pushDist)
            pushDist = curVec.distanceTo(nextVec);

          outlinePointRight1.subSelf(curveNormal1.scale(pushDist));
          outlinePointRight2.addSelf(curveNormal2.scale(pushDist));

        }

        if (outlinePointLeft1 != null && outlinePointLeft2 != null
            && outlinePointLeft1.distanceTo(outlinePointLeft2) > 0) {
          outlinePointLeft1.controlPoint1 = outlinePointLeft1
              .add(curveNormal1.scale(outlinePointLeft1
                  .distanceTo(outlinePointLeft2) / 2));
          outlinePointLeft2.controlPoint2 = outlinePointLeft2
              .sub(curveNormal2.scale(outlinePointLeft1
                  .distanceTo(outlinePointLeft2) / 2));
        }

        if (outlinePointRight1 != null
            && outlinePointRight2 != null
            && outlinePointRight1.distanceTo(outlinePointRight2) > 0) {
          outlinePointRight1.controlPoint2 = outlinePointRight1
              .add(curveNormal1.scale(outlinePointRight1
                  .distanceTo(outlinePointRight2) / 2));
          outlinePointRight2.controlPoint1 = outlinePointRight2
              .sub(curveNormal2.scale(outlinePointRight1
                  .distanceTo(outlinePointRight2) / 2));
        }

      }

      //

      /*
       * Finally add the offset points to the path
       */

      if (outlinePointLeft1 != null)
        this.outineLeft.add(outlinePointLeft1);

      if (outlinePointRight1 != null)
        this.outineRight.add(outlinePointRight1);

      if (outlinePointLeft2 != null)
        this.outineLeft.add(outlinePointLeft2);

      if (outlinePointRight2 != null)
        this.outineRight.add(outlinePointRight2);

    }


    /*
     * NOW approxomate Our bezier curve offset
     */
    int leftOffset = 0;
    int rightOffset = 0;
    getCentrePath().cacheLength(true);
   
    int loop = 1;
   
    if(getCentrePath().getClosed())
      loop = 0;

    for (int i = 0; i < getCentrePath().size() - loop; i++) {
      SketchPoint curPoint = getCentrePath().get(i);
     
      int nextIndex = i+1;
     
      if(i == getCentrePath().size()-1)
        nextIndex = 0;
     
      SketchPoint nextPoint = getCentrePath().get(nextIndex);
 

      tempOffset = this.getOffsetSize();
      tempOffsetNext = this.getOffsetSize();

      if (getCentreOffset().containsKey(i))
        tempOffset = this.getCentreOffset().get(i);

      if (nextPoint != null && getCentreOffset().containsKey(nextIndex)) {
        tempOffsetNext = this.getCentreOffset().get(nextIndex);
      }

      leftOffset++;
      rightOffset++;

      if ((curPoint.containsBezier() || nextPoint.containsBezier())) {
       

        float step = getParentSketch().getSketchGlobals().BEZIER_DETAIL_OFFSET;
        step /= getCentrePath().size();

        float pDelta = (getCentrePath().getPercent(nextPoint) - step)
            - (getCentrePath().getPercent(curPoint) + step);
        float p = 0;
        for (float s = getCentrePath().getPercent(curPoint) + step; s < getCentrePath()
            .getPercent(nextPoint) - step; s += step) {
          Vec2D curveVec = getCentrePath().getPos(s);
          Vec2D perp = getCentrePath().getPerpendicular(s);

          float offset = tempOffset;
          p += (step / pDelta);

          offset = (tempOffset * (1 - p)) + (tempOffsetNext * p);

          if(rightOffset < outineRight.size()){
          this.outineRight.add(
              rightOffset,
              new SketchPoint(curveVec.add(perp
                  .getRotated((float) (Math.PI / 2))
                  .normalize().scaleSelf(-offset))));
          rightOffset++;
          }
          if(leftOffset < outineLeft.size()){

          this.outineLeft.add(
              leftOffset,
              new SketchPoint(curveVec.add(perp
                  .getRotated((float) (Math.PI / 2))
                  .normalize().scaleSelf(offset))));
          leftOffset++;
          }

        }

      }

      leftOffset++;
      rightOffset++;

    }


    getCentrePath().cacheLength(false);

   

    /**
     * BUILD end caps
     *
     * ___
     * |:|
     * |:|
     * ---
     */
   
   
    applyOutlineOffset();
    buildPath();


    if (this.getCap() == SketchSpline.CAP_LEG && this.outineLeft.size() >= 2) {
     
      // remember starts and ends
      SketchPoint start = this.getCentrePath().get(0);
      SketchPoint startNext = this.getCentrePath().get(1);

      SketchPoint startLeft = this.outineLeft.get(0);
      SketchPoint startRight = this.outineRight.get(0);
      SketchPoint endPrev = this.getCentrePath().get(
          this.getCentrePath().size() - 2);
      SketchPoint end = this.getCentrePath().get(
          this.getCentrePath().size() - 1);
      SketchPoint endLeft = this.outineLeft
          .get(this.outineLeft.size() - 1);
      SketchPoint endRight = this.outineRight
          .get(this.outineRight.size() - 1);

      float a = (float) functions.angleOf(endLeft.copy().sub(endRight)
          .normalize());
      a = (float) (a - Math.PI);
      float Adjacent = end.distanceTo(endLeft);
      float Opposite = (float) (Math.tan(a) * Adjacent);
      float Hypotenues = (float) Math.sqrt(Math.pow(Adjacent, 2)
          + Math.pow(Opposite, 2));

      if (Hypotenues > end.distanceTo(endPrev))
        Hypotenues = end.distanceTo(endPrev);

      float flip = 1;

      //flip side
      if (a > (Math.PI / 2) || a < -(Math.PI / 2))
        flip = -flip;

      endLeft.y = end.y;
      endLeft.x = end.x + (Hypotenues * (-flip));
      endRight.y = end.y;
      endRight.x = end.x + (Hypotenues * flip);

      //endRight.y = end.y;

      float startLen = startLeft.distanceTo(startRight) / 2;
      float endLen = endLeft.distanceTo(endRight) / 2;
      // remove ends
      float totalLen = this.getlength();
      int arrayOffset = 1;

      Vec2D dir = startLeft.copy().sub(startRight).rotate((float) (Math.PI / 2));
      dir.normalize();

      Vec2D bezierLeftStart = this.outineLeft.get(0).copy();
      bezierLeftStart.addSelf(dir.scale(startLen * 1.5f));

      Vec2D bezierRightStart = this.outineRight.get(0).copy();
      bezierRightStart.addSelf(dir.scale(startLen * 1.5f));

      this.path.addBezier(
          startLeft,startLeft.copy(), bezierLeftStart
              .copy());
      this.path.addBezier(startRight,
          bezierRightStart.copy(), startRight.copy());

    }

    if (this.getCap() == SketchSpline.CAP_PARRALEL && this.outineLeft.size() >= 2) {
      // remember starts and ends
      SketchPoint start = this.getCentrePath().get(0);
      SketchPoint startNext = this.getCentrePath().get(1);

      SketchPoint startLeft = this.outineLeft.get(0);
      SketchPoint startRight = this.outineRight.get(0);
      SketchPoint endPrev = this.getCentrePath().get(
          this.getCentrePath().size() - 2);
      SketchPoint end = this.getCentrePath().get(
          this.getCentrePath().size() - 1);
      SketchPoint endLeft = this.outineLeft
          .get(this.outineLeft.size() - 1);
      SketchPoint endRight = this.outineRight
          .get(this.outineRight.size() - 1);

      float a = (float) functions.angleOf(endLeft.sub(endRight)
          .normalize());
      a = (float) (a - Math.PI);
      float Adjacent = end.distanceTo(endLeft);
      float Opposite = (float) (Math.tan(a) * Adjacent);
      float Hypotenues = (float) Math.sqrt(Math.pow(Adjacent, 2)
          + Math.pow(Opposite, 2));

      if (Hypotenues > end.distanceTo(endPrev))
        Hypotenues = end.distanceTo(endPrev);

      float flip = 1;

      //flip side
      if (a > (Math.PI / 2) || a < -(Math.PI / 2))
        flip = -flip;

      endLeft.y = end.y;
      endLeft.x = end.x + (Hypotenues * (-flip));
      endRight.y = end.y;
      endRight.x = end.x + (Hypotenues * flip);

      //endRight.y = end.y;

      //Other end

      a = (float) functions
          .angleOf(startLeft.sub(startRight).normalize());
      a = (float) (a - Math.PI);
      Adjacent = start.distanceTo(startLeft);
      Opposite = (float) (Math.tan(a) * Adjacent);
      Hypotenues = (float) Math.sqrt(Math.pow(Adjacent, 2)
          + Math.pow(Opposite, 2));

      if (Hypotenues > start.distanceTo(startNext))
        Hypotenues = start.distanceTo(startNext);

      flip = 1;

      //flip side
      if (a > (Math.PI / 2) || a < -(Math.PI / 2))
        flip = -flip;

      startLeft.y = start.y;
      startLeft.x = start.x + (Hypotenues * (-flip));
      startRight.y = start.y;
      startRight.x = start.x + (Hypotenues * flip);
      //endRight.y = end.y;

    }

   
   
   
    if (this.getCap() == SketchSpline.CAP_ROUND && this.outineLeft.size() >= 2) {
      // remember starts and ends
      SketchPoint startLeft = this.outineLeft.get(0);
      SketchPoint startRight = this.outineRight.get(0);
      SketchPoint endLeft = this.outineLeft
          .get(this.outineLeft.size() - 1);
      SketchPoint endRight = this.outineRight
          .get(this.outineRight.size() - 1);

      float startLen = startLeft.distanceTo(startRight) / 2;
      float endLen = endLeft.distanceTo(endRight) / 2;
      // remove ends
      float totalLen = this.getlength();
      int arrayOffset = 1;

      Vec2D dir = startLeft.copy().sub(startRight).rotate((float) (Math.PI / 2));
      dir.normalize();

      Vec2D bezierLeftStart = this.outineLeft.get(0).copy();
      bezierLeftStart.addSelf(dir.scale(startLen * 1.5f));

      Vec2D bezierRightStart = this.outineRight.get(0).copy();
      bezierRightStart.addSelf(dir.scale(startLen * 1.5f));

     
      this.path.addBezier(
          startLeft,
      startLeft.copy(), bezierLeftStart
              .copy());
      this.path.addBezier(startRight,
          bezierRightStart.copy(), startRight.copy());

      /*
       * END Cap now
       */

      Vec2D dirEnd = endLeft.copy().sub(endRight).rotate((float) (Math.PI / 2));
      dirEnd.normalize();

      Vec2D bezierLeftEnd = this.outineLeft.get(
          this.outineLeft.size() - 1).copy();
      bezierLeftEnd.subSelf(dirEnd.scale(endLen * 1.5f));

      Vec2D bezierRightEnd = this.outineRight.get(
          this.outineRight.size() - 1).copy();
      bezierRightEnd.subSelf(dirEnd.scale(endLen * 1.5f));

 
      // bezierLeftEnd.addSelf(new Vec2D(100,100));

     
      this.path
          .addBezier(
              endLeft,bezierLeftEnd.copy(), endLeft
                  .copy());
      this.path.addBezier(endRight,
          endRight.copy(), bezierRightEnd.copy());

      //}

      /*
      if (this.offsetType == SketchSpline.OFFSET_RIGHT
          || this.offsetType == SketchSpline.OFFSET_BOTH
          && this.outineRight.size() > 0) {

        int offset = 0;
        if (this.offsetType == SketchSpline.OFFSET_BOTH)
          offset++;

      }
      */
    }

    /**
     * CAP BUTT
     */

    if (this.getCap() == SketchSpline.CAP_BUTT) {

      applyOutlineOffset();
      buildPath();
    }

    this.isBuilt = true;

  }

  public void optimize() {

    if (!autoSmooth || this.getType() == SketchSpline.OFFSET_SPLINE)
      return;

    if (getCentrePath().size() < 3)
      return;

    // System.out.println("optimize sketch");

    SketchPoint lastStoredPoint = (SketchPoint) getCentrePath().get(0);
    List<SketchPoint> optimizedArray = new ArrayList<SketchPoint>();
    optimizedArray.add(lastStoredPoint);

    float step = SETTINGS_SKETCH.spline_point_every / this.getlength();
    for (float i = step; i < 1 ; i += step) {
      optimizedArray.add(new SketchPoint(this.getPos(i)));
    }
    optimizedArray.add(getCentrePath().get(getCentrePath().size() - 1));
    // go through and add selected points replacing the closesed points to
    // these
    getCentrePath().setPath((ArrayList<SketchPoint>) optimizedArray);

    for (int i = 0; i < this.getSelectedNodes().size(); i++) {
      Object objNode =  this.getSelectedNodes()
          .get(i);
     
      if(objNode instanceof SketchPoint){
      SketchPoint selectedNode =  (SketchPoint)objNode;
     
      int index = this.getNearestVecIndex(selectedNode);
      getCentrePath().set(index, selectedNode);
      // centrePath.l.remove(index);
      // centrePath.l.add(index, selectedNode);
      }
    }
  }

  public void optimizeRange(Vec2D startVec, Vec2D endVec) {

    if (!autoSmooth || this.getType() == SketchSpline.OFFSET_SPLINE)
      return;

    if (getCentrePath().size() < 3)
      return;

    // build arrays
    ArrayList<SketchPoint> startList = new ArrayList<SketchPoint>();
    ArrayList<SketchPoint> middleList = new ArrayList<SketchPoint>();
    ArrayList<SketchPoint> endList = new ArrayList<SketchPoint>();

    // get the index of the start and end point
    int startIndex = this.getIndex(startVec);
    int endIndex = this.getIndex(endVec);

    // flags
    Vec2D beforeStart = null;
    Vec2D afterEnd = null;

    if (startIndex > 0)
      beforeStart = (Vec2D) getCentrePath().get(startIndex - 1);

    if (endIndex < getCentrePath().size() - 1)
      afterEnd = (Vec2D) getCentrePath().get(endIndex + 1);

    // build the start
    for (int i = 0; i < startIndex - 2; i++) {
      SketchPoint vec = (SketchPoint) getCentrePath().get(i);
      startList.add(vec);

    }

    // System.out.println("startPos" + this.getLenTo(beforeStart));

    float step = SETTINGS_SKETCH.spline_point_every / this.getlength();
    // store the start percent of our offset
    float startPos = this.getLenTo(beforeStart) / this.getlength();

    if (beforeStart == null)
      startPos = 0;

    float endPos = this.getLenTo(afterEnd) / this.getlength();

    if (afterEnd == null)
      endPos = 1;

    // System.out.println("start percent:"+startPos + " index:" +
    // startIndex+ "    end percent:" + endPos + " index:" + endIndex +
    // "     total len:" + centrePath.size() + "  step:" + step);

    for (float i = startPos; i < endPos; i += step) {
      // System.out.println("adding to middle" + i);

      Vec2D addVec = this.getPos(i);
      SketchPoint addP = new SketchPoint(addVec);
      // if(i < 1 && addVec.distanceTo(startVec) >
      // SETTINGS_SKETCH.spline_point_every && addVec.distanceTo(endVec) >
      // SETTINGS_SKETCH.spline_point_every)

      if (i < 1 - step)
        ;
      middleList.add(addP);

    }

    for (int i = endIndex; i < getCentrePath().size(); i++) {
      SketchPoint vec = (SketchPoint) getCentrePath().get(i);
      endList.add(vec);
    }

    for (int i = 0; i < middleList.size(); i++) {
      SketchPoint vec = middleList.get(i);
      startList.add(vec);
    }

    for (int i = 0; i < endList.size(); i++) {
      SketchPoint vec = endList.get(i);
      startList.add(vec);
    }

    getCentrePath().setPath(startList);

    for (int i = 0; i < this.getSelectedNodes().size(); i++) {
      SketchPoint selectedNode = (SketchPoint) this.getSelectedNodes()
          .get(i);
      int index = this.getNearestVecIndex(selectedNode);

      if (index != -1)
        getCentrePath().set(index, selectedNode);
      // centrePath.l.remove(index);
      // centrePath.l.add(index, selectedNode);

    }

  }

  public void removeVertex(SketchPoint v) {
    if (this.getCentrePath().contains(v)) {
      this.getCentrePath().remove(v);
      this.build();
    }

    if (this.getCentrePath().size() == 1)
      this.destroy();

  }

  public void render(PGraphics g) {

   
   
    Sketch s = getParentSketch();
    SketchTools st = s.getSketchTools();
   
    this.path.editable = false;
    this.path.setParentSketch(this.getParentSketch());
    this.path.render(g);
    this.centrePath.editable = true;
    this.centrePath.setType(this.getType());
    this.centrePath.setClosed(false);
   
   
   
    switch(getParentSketch().getRenderMode()){
    case Sketch.RENDER_3D_PREVIW:
    break;
     
    case Sketch.RENDER_3D_EDITING_PLANES:
      this.centrePath.render(g);
    break;
     
    case Sketch.RENDER_3D_DIAGRAM:
    break;
   
    case Sketch.RENDER_EDIT_SELECT:

    break;
   
    }
   
    /*
   

    if (getParentSketch().getSketchTools().getCurrentTool() != SketchTools.SELECT_TOOL) {
      if (this.getParentSketch().isSelected()) { // is parent layer
        g.fill(getParentSketch().getSketchGlobals().chairColour);
      } else {
        g.fill(SETTINGS_SKETCH.SKETCHSHAPE_FILL_UNSELECTED_LAYER_COLOUR);

      }
    } else {
    }



    if (this.isBuilt) {
      this.path.setParentSketch(this.getParentSketch());
      this.path.render(g);

    } else {
      // draw selection points
      if (getParentSketch().getSketchTools().getCurrentTool() == SketchTools.SELECT_TOOL
          && !getParentSketch().getSketchTools().mouseDown) {

        float selectDia = SETTINGS_SKETCH.select_dia
            * (1 / getParentSketch().getSketchGlobals().zoom);

        if (selectDia > SETTINGS_SKETCH.select_dia * 1.5f)
          selectDia = SETTINGS_SKETCH.select_dia;

        for (int i = 0; i < getCentrePath().size(); i++) {
          Vec2D curVec = (Vec2D) getCentrePath().get(i);
          g.ellipse(curVec.x, curVec.y, selectDia, selectDia);
        }
      }

      if (SETTINGS_SKETCH.fill_sketch
          && getParentSketch().getSketchTools().getCurrentTool() != SketchTools.SELECT_TOOL) {
        if (selected) {
          g.fill(SETTINGS_SKETCH.SKETCHSHAPE_FILL_SELECTED_COLOUR);
        } else {
          g.fill(getParentSketch().getSketchGlobals().chairColour);
        }
      } else {
        g.noFill();
      }

      // ------------------------------------------------
      if (this.getCombinedSize() > 0) {
        g.beginShape();

        for (int i = this.getCombinedSize() - 1; i > -1; i--) {
          Vec2D curVec = (Vec2D) this.getCombined(i);

          if (SETTINGS_SKETCH.Draw_Curves)
            g.curveVertex(curVec.x, curVec.y);
          else
            g.vertex(curVec.x, curVec.y);
        }

        Vec2D curVec = (Vec2D) this
            .getCombined(this.getCombinedSize() - 1);

        if (SETTINGS_SKETCH.Draw_Curves) {
          g.curveVertex(curVec.x, curVec.y);
          g.curveVertex(curVec.x, curVec.y);

        } else {
          g.vertex(curVec.x, curVec.y);
          g.vertex(curVec.x, curVec.y);
        }

      }

      g.endShape();
      g.noFill();

    }

    this.centrePath.editable = true;
    this.centrePath.setClosed(false);
   
   
   
   
      switch(getParentSketch().getRenderMode()){
      case Sketch.RENDER_3D_PREVIW:
      break;
       
      case Sketch.RENDER_3D_EDITING_PLANES:
       
       
        renderNodes(g);
       
        //this.centrePath.render(g);
      break;
       
      case Sketch.RENDER_3D_DIAGRAM:
      break;
     
      }
      */
  }

  private void renderNodes(PGraphics g) {

    float selectDia = SETTINGS_SKETCH.select_dia
        * (1 / getParentSketch().getZOOM());

    if (selectDia > SETTINGS_SKETCH.select_dia * 1.5f)
      selectDia = SETTINGS_SKETCH.select_dia;

    selectDia = selectDia / 2;

    if (true) {
      // g.fill(SETTINGS_SKETCH.sChair_controle_points_fill);
      g.noFill();
      g.stroke(SETTINGS_SKETCH.CONTROL_POINT_STROKE_COLOUR);
      g.fill(SETTINGS_SKETCH.CONTROL_POINT_FILL_COLOUR);
     
      Vec2D startVect = (Vec2D) getCentrePath().get(0);
      if(startVect != null)
      g.ellipse(startVect.x, startVect.y, selectDia,selectDia);
     
      Vec2D endVect = (Vec2D) getCentrePath().get(getCentrePath().size()-1);
      if(startVect != null)
      g.ellipse(endVect.x, endVect.y, selectDia,selectDia);
     
     
      g.noFill();
      g.beginShape()
      for (int i = 0; i < getCentrePath().size(); i++) {
        Vec2D curVec = (Vec2D) getCentrePath().get(i);
       
        g.vertex(curVec.x,curVec.y);
       
        //
        // selectDia);
      }
      g.endShape();

      g.noFill();
    }
  }


  public void renderPickBuffer(PGraphics g) {
    //g.noStroke();
 
    this.path.renderPickBuffer(g);


  }

  public void renderSilhouette(PGraphics g) {
    this.path.renderSilhouette(g);
  }

  public void replace(SketchShape clone) {

    SketchSpline cloneLocal = (SketchSpline) clone;

    getCentrePath().setPath(cloneLocal.getCentrePath().getList());
    this.outineLeft = cloneLocal.outineLeft;
    this.outineRight = cloneLocal.outineRight;
    this.slots = cloneLocal.slots;

    this.setOffsetSize(cloneLocal.getOffsetSize());
    this.path = cloneLocal.path;
    this.path.editable = false;
    this.isBuilt = cloneLocal.isBuilt;
    this.offsetType = cloneLocal.offsetType;

  }

  public void scale(float scale, toxi.geom.Vec3D centre) {
    // this.scale += scale;
    this.setOffsetSize(this.getOffsetSize()
        + (this.getOffsetSize() * scale));
    this.getCentrePath().scale(scale, centre);
    this.path.scale(scale, centre);
  }

  public void select() {
    this.selected = true;
    if (this.path != null)
      this.path.select();
   
    this.getCentrePath().select();
  }
 
  public void unselect() {
       
   
    this.selected = false;
   
    if (this.path != null)
      this.path.unselect();
   
    this.getCentrePath().unselect();


  }
 

  public void selectNodes(float mouseX, float mouseY) {
    // this.path.selectNodes(mouseX, mouseY);

    boolean shapeSelected = false;
    float selectDia = SETTINGS_SKETCH.select_dia
        * (1 / getParentSketch().getZOOM());

    if (selectDia > SETTINGS_SKETCH.select_dia * 1.5f)
      selectDia = SETTINGS_SKETCH.select_dia;

    this.unselectNodes();
    this.path.unselectNodes();
    for (int i = 0; i < getCentrePath().size(); i++) {
      SketchPoint v = (SketchPoint) getCentrePath().get(i);
      if (v.distanceTo(new Vec2D(mouseX, mouseY)) < selectDia) {
        this.getSelectedNodes().add(v);
        shapeSelected = true;
      }
    } // TODO Auto-generated method stub

    if (shapeSelected && getParentSketch().getSketchGlobals().undo != null)
      getParentSketch().getSketchGlobals().undo
          .addOperation(new UndoAction(this, this.clone(),
              UndoAction.EDIT_SHAPE));

    //if (!shapeSelected)
    this.getCentrePath().selectNodes(mouseX, mouseY);

    if (this.path.getSelectedNodes().size() > 0 && !shapeSelected)
      getParentSketch().getSketchGlobals().undo
          .addOperation(new UndoAction(this, this.clone(),
              UndoAction.EDIT_SHAPE));

  }

  public void setCap(int cap) {
    capType = cap;
  }


  public void setCentreOffset(Map<Integer, Float> centreOffset) {
    this.centreOffset = centreOffset;
  }


  public void setCentrePath(SketchPath centrePath) {
    this.centrePath = centrePath;
  }

  public void setJoinType(int j) {
    this.joinType = j;
  }


  public void setOffsetSize(float offsetSize) {
    this.offsetSize = offsetSize;
  }

  public void setOffsetSizeCentre(float val) {
    for (int i = 0; i < this.getCentrePath().getSelectedNodes().size(); i++) {
      SketchPoint p = (SketchPoint) this.getCentrePath()
          .getSelectedNodes().get(i);
      int index = this.getCentrePath().l.indexOf(p);
      this.getCentreOffset().put(index, val);
    }
  }
 

  public SketchPoint setVec2DpickBuffer(int col, SketchPoint selectedVec,
      SketchShape selectedShape, SlicePlane selectedVecPlane,
      boolean isSelectedVecOnOutline) {

    for (int i = 0; i < getCentrePath().size(); i++) {
      SketchPoint curVec = (SketchPoint) getCentrePath().get(i);

      if (col == getColor(i + (this.id * 100))) {
        isSelectedVecOnOutline = false;
        selectedShape = this;
        selectedVec = curVec;

        return selectedVec;
      }
    }

    for (int i = 0; i < this.getCombinedSize(); i++) {
      SketchPoint curVec = (SketchPoint) this.getCombined(i);
      if (col == getColor(getCentrePath().size() + i + (this.id * 100))) {
        isSelectedVecOnOutline = true;
        selectedShape = this;
        selectedVec = curVec;
        return selectedVec;
      }
    }
    selectedVec = null;
    return null;

  }

  public Element toXML() {
    Element element = new Element("SketchSpline");

    element.addAttribute(new Attribute("id", String.valueOf(this.getId())));
    element.addAttribute(new Attribute("outlineId", String
        .valueOf(this.path.getId())));
    element.addAttribute(new Attribute("centreId", String.valueOf(this
        .getCentrePath().getId())));

    element.addAttribute(new Attribute("offsetSize", String.valueOf(this
        .getOffsetSize())));

    element.addAttribute(new Attribute("splineType", String.valueOf(this
        .getType())));

    element.addAttribute(new Attribute("endCap", String.valueOf(this
        .getCap())));

    element.addAttribute(new Attribute("joinType", String.valueOf(this
        .getJoinType())));


    if (isConstructionLine())
      element.addAttribute(new Attribute("isConstructionLine", "true"));

    element.addAttribute(new Attribute("union", String.valueOf(this.union)));

    Element elementCentre = new Element("SketchSplineCentrePath");
    for (int i = 0; i < this.getCentrePath().size(); i++) {
      SketchPoint point = this.getCentrePath().get(i);
      elementCentre.appendChild(point.toXML());
    }

    element.appendChild(elementCentre);

    Element SketchSplineOffsets = new Element("SketchSplineOffsets");
    for (int i = 0; i < getCentrePath().size(); i++) {
      SketchPoint curVec = (SketchPoint) getCentrePath().get(i);

      if (this.outlineOffset.containsKey(i)) {
        Vec2D offset = this.outlineOffset.get(i);
        Element SketchSplineOffset = new Element("SketchSplineOffset");
        SketchSplineOffset.addAttribute(new Attribute("linked_id",
            String.valueOf(i)));
        SketchSplineOffset.addAttribute(new Attribute("x_offset",
            String.valueOf(offset.x)));
        SketchSplineOffset.addAttribute(new Attribute("y_offset",
            String.valueOf(offset.y)));

        SketchSplineOffsets.appendChild(SketchSplineOffset);
      }

    }

    Element SketchSplinePathOffsets = new Element("SketchSplinePathOffsets");
    for (int i = 0; i < getCentrePath().size(); i++) {
      SketchPoint curVec = (SketchPoint) getCentrePath().get(i);

      if (this.getCentreOffset().containsKey(i)) {
        float offset = this.getCentreOffset().get(i);
        Element SketchSplineOffset = new Element(
            "SketchSplinePathOffset");
        SketchSplineOffset.addAttribute(new Attribute("linked_index",
            String.valueOf(i)));
        SketchSplineOffset.addAttribute(new Attribute("offset", String
            .valueOf(offset)));

        SketchSplinePathOffsets.appendChild(SketchSplineOffset);
      }

    }

    element.appendChild(SketchSplinePathOffsets);

    for (int i = 0; i < getCentrePath().size(); i++) {
      Vec2D curVec = (Vec2D) getCentrePath().get(i);
      int i2 = ((getCentrePath().size() * 2) - i - 1);

      if (this.outlineOffset.containsKey(i2)) {
        Vec2D offset = this.outlineOffset.get(i2);

        Element SketchSplineOffset = new Element("SketchSplineOffset");

        SketchSplineOffset.addAttribute(new Attribute("linked_id",
            String.valueOf(i2)));
        SketchSplineOffset.addAttribute(new Attribute("x_offset",
            String.valueOf(offset.x)));
        SketchSplineOffset.addAttribute(new Attribute("y_offset",
            String.valueOf(offset.y)));

        SketchSplineOffsets.appendChild(SketchSplineOffset);

      }

    }

    element.appendChild(SketchSplineOffsets);

    return element;
  }



}
TOP

Related Classes of cc.sketchchair.sketch.SketchSpline

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.