/******************************************************************************* * 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; } }