/*******************************************************************************
* 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/>.
******************************************************************************/
package cc.sketchchair.core;
import java.util.ArrayList;
import java.util.List;
import cc.sketchchair.geometry.SlicePlane;
import cc.sketchchair.geometry.SlicePlanes;
import cc.sketchchair.sketch.Sketch;
import cc.sketchchair.sketch.SketchPath;
import cc.sketchchair.sketch.SketchShape;
import cc.sketchchair.sketch.SketchSpline;
import cc.sketchchair.sketch.SketchTools;
import nu.xom.Attribute;
import nu.xom.Element;
import nu.xom.Elements;
import ModalGUI.GUIEvent;
import processing.core.PGraphics;
import toxi.geom.Plane;
import toxi.geom.Vec2D;
import toxi.geom.Vec3D;
/**
* This Class holds parameters for generating slice selections.
*
* <pre>
* start
* /|/|/|/|/|
* 0.1f -----------< --- (crossSliceSelection)
* / / / / /
* 0.2f -----------<
* / / / / /
* 0.3f -----------<
* |/|/|/|/|/
* end
*
* </pre>
*/
public class CrossSliceSelection implements Clickable {
public static final int SLATSLICES = 4;
public static final int PLANE = 5;
public static int SINGLE_SLICE = 3;
public static int SLICES = 0;
public static int LEG = 1;
public static int PLANE_ON_EDGE = 2;
public static int CAP_CURVE = 1;
public static int CAP_BUTT = 2;
public static int CAP_INSIDE = 3;
public static int CAP_ROUND_SQUARE = 4;
public static int JOIN_CURVE = 1;
public static int JOIN_STRAIGHT = 2;
public int type = SLICES;
public SketchShape path = null;
public float start = 0;
public float end = .5f;
boolean editing = false;
public SlicePlane plane = null;
public SlicePlanes planes = new SlicePlanes();;
public boolean extendLegSliceToTopOfLeg = false;
public float mousePercent;
public boolean cropToCurrentShape = true;
public boolean tieToLeg = false;
//boolean top = false;
public boolean flipSide = false;
int clicks = 0;
public float spacing = 0.9f;
public boolean destroy;
public ArrayList tiedToPlanes = new ArrayList();
public SketchSpline legSpline;
public SketchChair parentChair;
public float boarderX = 0;
public float boarderY = 0;
public boolean selected = false;
private boolean mouseOnButton = false;
public float slatHeight = 0;
public float teethCount = 5;
public int capType = CAP_CURVE;
public int joinType = JOIN_STRAIGHT;
public float offsetRotation = 0f;
public float cornerRadius = 10;
public boolean smooth = false;
public boolean generateFlushTops = false;
public float fingerTollerance = 0.0f;
public List<Sketch> legSplines = null;
public boolean tempSlice = false;
public CrossSliceSelection() {
// TODO Auto-generated constructor stub
}
//#IF JAVA
public CrossSliceSelection(Element element, SlicePlanes linkedPlanes,
SketchChair linkedChair) {
//wrong type
if (!element.getLocalName().equals("CrossSliceSelection"))
return;
if (element.getAttributeValue("path") != null
&& element.getAttributeValue("start") != null
&& element.getAttributeValue("end") != null
&& element.getAttributeValue("spacing") != null) {
if (element.getAttributeValue("boarderX") != null)
this.boarderX = Float.valueOf(element
.getAttributeValue("boarderX"));
if (element.getAttributeValue("boarderY") != null)
this.boarderY = Float.valueOf(element
.getAttributeValue("boarderY"));
if (element.getAttributeValue("slatHeight") != null)
this.slatHeight = Float.valueOf(element
.getAttributeValue("slatHeight"));
if (element.getAttributeValue("teethCount") != null)
this.teethCount = Float.valueOf(element
.getAttributeValue("teethCount"));
if (element.getAttributeValue("capType") != null)
this.capType = Integer.valueOf(element
.getAttributeValue("capType"));
if(element.getAttributeValue("extendLegSliceToTopOfLeg") != null)
extendLegSliceToTopOfLeg = Boolean.valueOf(element.getAttributeValue("extendLegSliceToTopOfLeg")).booleanValue() ;
int linkedSketchId = Integer.valueOf(element
.getAttributeValue("path"));
if (linkedPlanes.getSketchShapeById(linkedSketchId) != null) {
this.path = linkedPlanes.getSketchShapeById(linkedSketchId);
//System.out.println("linked sketch");
}
this.start = Float.valueOf(element.getAttributeValue("start"));
this.end = Float.valueOf(element.getAttributeValue("end"));
this.spacing = Float.valueOf(element.getAttributeValue("spacing"));
if (element.getAttributeValue("type") != null)
this.type = Integer.valueOf(element.getAttributeValue("type"));
if (element.getAttributeValue("tieToLeg") != null) {
this.tieToLeg = true;
if (element.getAttributeValue("legId") != null) {
this.legSpline = (SketchSpline) linkedPlanes
.getSketchShapeById(Integer.valueOf(element
.getAttributeValue("legId")));
}
}
if (element.getFirstChildElement("legPlanes") != null) {
Element legElements = element.getFirstChildElement("legPlanes");
for (int i = 0; i < legElements.getChildCount(); i++) {
Element child = (Element) legElements.getChild(i);
if (child != null && child.getLocalName().equals("legPlane")) {
if (child.getAttributeValue("planeId") != null){
int planeId = Integer.parseInt(child.getAttributeValue("planeId"));
//LOGGER.info(linkedPlanes + "linkedPlanes");
SlicePlane linkedPlane = (SlicePlane) linkedPlanes.getById(planeId);
if(linkedPlane != null)
this.tiedToPlanes.add(linkedPlane);
}
}
}
}
if (element.getAttributeValue("constrainToShape") != null)
this.cropToCurrentShape = true;
else
this.cropToCurrentShape = false;
if (element.getAttributeValue("flipSide") != null)
this.flipSide = true;
if (element.getAttributeValue("generateFlushTops") != null)
this.generateFlushTops = true;
if (element.getAttributeValue("smooth") != null)
this.smooth = true;
this.plane = linkedPlanes.getPlaneContainingShape(this.path);
GLOBAL.uiTools.addListener(this);
editing = false;
this.parentChair = linkedChair;
} else {
}
}
public CrossSliceSelection(SketchShape spline, SlicePlane plane,
float start, float end, float spacing, SketchChair chair) {
this.path = spline;
this.start = start;
this.spacing = spacing;
this.end = end;
this.plane = plane;
GLOBAL.uiTools.addListener(this);
editing = false;
this.parentChair = chair;
}
public CrossSliceSelection(SketchShape curSpline, SlicePlane extrudeSlice,
SketchChair chair) {
this(curSpline, extrudeSlice, 0, 1, 10, chair);
}
public CrossSliceSelection copy(SlicePlanes slicePlanes,
SketchChair linkedChair) {
CrossSliceSelection newCrossSliceSelection = new CrossSliceSelection();
newCrossSliceSelection.start = this.start;
newCrossSliceSelection.end = this.end;
newCrossSliceSelection.spacing = this.spacing;
newCrossSliceSelection.type = this.type;
newCrossSliceSelection.boarderX = this.boarderX;
newCrossSliceSelection.boarderY = this.boarderY;
newCrossSliceSelection.slatHeight = this.slatHeight;
newCrossSliceSelection.tieToLeg = this.tieToLeg;
newCrossSliceSelection.extendLegSliceToTopOfLeg = this.extendLegSliceToTopOfLeg;
newCrossSliceSelection.cropToCurrentShape = this.cropToCurrentShape;
newCrossSliceSelection.flipSide = this.flipSide;
newCrossSliceSelection.teethCount = this.teethCount;
if (this.path != null
&& slicePlanes.getSketchShapeById(this.path.getId()) != null) {
newCrossSliceSelection.path = slicePlanes
.getSketchShapeById(this.path.getId());
}
if (this.legSpline != null
&& slicePlanes.getSketchShapeById(this.legSpline.getId()) != null) {
newCrossSliceSelection.legSpline = (SketchSpline) slicePlanes
.getSketchShapeById(this.legSpline.getId());
}
if(this.tiedToPlanes !=null){
for(int i = 0; i < slicePlanes.size(); i++){
SlicePlane slicePlane = (SlicePlane)slicePlanes.get(i);
}
for(int i = 0; i < this.tiedToPlanes.size(); i++){
SlicePlane slicePlane = (SlicePlane)this.tiedToPlanes.get(i);
SlicePlane linkedSlicePlane = (SlicePlane) slicePlanes.getById(slicePlane.getId());
if(linkedSlicePlane != null)
newCrossSliceSelection.tiedToPlanes.add(linkedSlicePlane);
}
}
if (newCrossSliceSelection.path != null)
newCrossSliceSelection.plane = slicePlanes
.getPlaneContainingShape(newCrossSliceSelection.path);
newCrossSliceSelection.parentChair = linkedChair;
newCrossSliceSelection.editing = false;
return newCrossSliceSelection;
}
public void destroy(GUIEvent e) {
this.destroy = true;
if (GLOBAL.slicesWidget != null)
GLOBAL.slicesWidget.removeRow(this);
}
public void edit(GUIEvent e) {
this.parentChair.unselectAllPlanes();
GLOBAL.uiTools.selectTool(UITools.CROSSSLICE_EDIT);
this.editing = true;
this.plane.select();
this.path.select();
clicks = 0;
GLOBAL.uiTools.setCurrentTool(UITools.SLICES_EDIT);
}
public void flipSide(GUIEvent e) {
this.flipSide = !this.flipSide;
this.parentChair.buildLen();
}
public int getCapType() {
return this.capType;
}
public int getJoinType() {
return this.joinType;
}
/**
* @return the slatHeight
*/
public float getSlatHeight() {
return slatHeight;
}
//@Override
public void mouseClicked() {
// TODO Auto-generated method stub
}
//@Override
public void mouseDragged() {
// TODO Auto-generated method stub
}
//@Override
public void mousePressed() {
// TODO Auto-generated method stub
}
//@Override
public void mouseReleased() {
//if(GLOBAL.uiTools.currentTool != UITools.CROSSSLICE_EDIT)
// return;
//System.out.println("CLICKED");
if (editing) {
clicks++;
//any click will add the currnt slice
if(this.type == CrossSliceSelection.SINGLE_SLICE){
editing = false;
clicks = 0;
return;
}
if(this.type ==CrossSliceSelection.PLANE ||
this.type ==CrossSliceSelection.PLANE_ON_EDGE ){
if (clicks == 2) {
editing = false;
clicks = 0;
return;
}
}
if(this.type == CrossSliceSelection.SLICES ||
this.type == CrossSliceSelection.SLATSLICES
){
if (clicks == 1) {
this.start = this.mousePercent;
}
if (clicks == 2) {
this.end = this.mousePercent;
}
if (clicks >= 3) {
editing = false;
clicks = 0;
return;
}
}
}
}
public void render(PGraphics g) {
if (this.path == null)
return;
if (selected || editing) {
/*
Vec2D mousePos = this.path.getPos(this.mousePercent);
g.ellipse(mousePos.x, mousePos.y, 20,20);
Vec2D startPos = this.path.getPos(this.start);
if(startPos != null)
g.ellipse(startPos.x, startPos.y, 20,20);
Vec2D endPos = this.path.getPos(this.end);
if(endPos != null)
g.ellipse(endPos.x, endPos.y, 20,20);
*/
}
}
public void select() {
//this.plane.select();
this.selected = true;
}
//#ENDIF JAVA
public void select(GUIEvent e) {
mouseOnButton = true;
}
public void setCapType(GUIEvent e) {
this.capType = (int) e.val;
}
public void setJoinType(GUIEvent e) {
this.joinType = (int) e.val;
}
/**
* @param slatHeight the slatHeight to set
*/
public void setSlatHeight(float slatHeight) {
this.slatHeight = slatHeight;
}
public void setSlatHeight(GUIEvent e) {
this.setSlatHeight(Float.parseFloat(e.getString()));
}
public void smooth(GUIEvent e) {
this.smooth = !this.smooth;
}
public void generateFlushTops(GUIEvent e) {
this.generateFlushTops = !this.generateFlushTops;
}
public void toggleConstrainToshape(GUIEvent e) {
this.cropToCurrentShape = !this.cropToCurrentShape;
this.parentChair.buildLen();
}
public void toggleSliceMode(GUIEvent e) {
if (this.type == CrossSliceSelection.LEG
|| this.type == CrossSliceSelection.SLICES)
this.type = CrossSliceSelection.PLANE_ON_EDGE;
else
this.type = CrossSliceSelection.SLICES;
this.flipSide = !flipSide;
this.parentChair.buildLen();
}
public nu.xom.Element toXML() {
Element element = new Element("CrossSliceSelection");
element.addAttribute(new Attribute("path", String.valueOf(this.path
.getId())));
element.addAttribute(new Attribute("start", String.valueOf(this.start)));
element.addAttribute(new Attribute("end", String.valueOf(this.end)));
element.addAttribute(new Attribute("spacing", String
.valueOf(this.spacing)));
element.addAttribute(new Attribute("type", String.valueOf(this.type)));
element.addAttribute(new Attribute("boarderX", String
.valueOf(this.boarderX)));
element.addAttribute(new Attribute("boarderY", String
.valueOf(this.boarderY)));
element.addAttribute(new Attribute("slatHeight", String
.valueOf(this.slatHeight)));
element.addAttribute(new Attribute("capType", String
.valueOf(this.capType)));
if (type == CrossSliceSelection.PLANE
|| type == CrossSliceSelection.PLANE_ON_EDGE
|| type == CrossSliceSelection.SLATSLICES)
element.addAttribute(new Attribute("teethCount", String
.valueOf(this.teethCount)));
if(extendLegSliceToTopOfLeg)
element.addAttribute(new Attribute("extendLegSliceToTopOfLeg", String
.valueOf(this.extendLegSliceToTopOfLeg)));
if (this.tieToLeg) {
element.addAttribute(new Attribute("tieToLeg", String
.valueOf(this.tieToLeg)));
element.addAttribute(new Attribute("legId", String
.valueOf(this.legSpline.getId())));
Element planeElement = new Element("legPlanes");
for (int i = 0; i < this.tiedToPlanes.size(); i++) {
SlicePlane curSlice = (SlicePlane)this.tiedToPlanes.get(i);
Element legPlane = new Element("legPlane");
legPlane.addAttribute(new Attribute("planeId", String
.valueOf(curSlice.getId())));
planeElement.appendChild(legPlane);
}
element.appendChild(planeElement);
}
if (this.cropToCurrentShape)
element.addAttribute(new Attribute("constrainToShape", String
.valueOf(this.cropToCurrentShape)));
if (this.flipSide)
element.addAttribute(new Attribute("flipSide", String
.valueOf(this.flipSide)));
if (this.generateFlushTops)
element.addAttribute(new Attribute("generateFlushTops", String
.valueOf(this.generateFlushTops)));
if (this.smooth)
element.addAttribute(new Attribute("smooth", String
.valueOf(this.smooth)));
return element;
}
public void unselect() {
// this.plane.unselect();
this.selected = false;
planes.unselectAll();
}
public void update() {
if (this.plane == null)
return;
if (editing && this.type != CrossSliceSelection.PLANE) {
if(this.path != null)
this.path.highlight();
//GLOBAL.uiTools.setCurrentTool(UITools.SLICES_GROUP_SLICES);
Vec2D pointOnPlan = GLOBAL.uiTools.getPointOnPlane(new Vec2D(
GLOBAL.uiTools.mouseX, GLOBAL.uiTools.mouseY), this.plane
.getPlane());
this.mousePercent = this.path.getClosestPercent(pointOnPlan.x,
pointOnPlan.y);
// LOGGER.info("UPDATE SLICE clicks "+clicks + " percent " +this.mousePercent );
if (this.type == CrossSliceSelection.SINGLE_SLICE) {
if (clicks == 0) {
this.start = this.mousePercent;
this.end = this.mousePercent;
}
if (clicks == 1) {
editing = false;
this.plane.unselect();
this.path.unselect();
}
} else {
GLOBAL.uiTools.sliceToolMode = UITools.SLICE_EDIT_MODE_SPACING;
if (clicks == 0) {
this.start = this.mousePercent;
GLOBAL.uiTools.sliceToolMode = UITools.SLICE_EDIT_MODE_ADD;
}
if (clicks == 1) {
this.end = this.mousePercent;
GLOBAL.uiTools.sliceToolMode = UITools.SLICE_EDIT_MODE_POS;
}
if (clicks == 2) {
float spacingVal = Math.abs(this.mousePercent - this.end);
this.spacing = spacingVal * 300;
}
if(clicks == 3){
// this.plane.unselect();
// this.path.unselect();
GLOBAL.uiTools.SketchTools.selectTool(SketchTools.SELECT_TOOL);
// editing = false;
// clicks = 0;
// return;
}
}
if ((this.type == CrossSliceSelection.SLICES || this.type == CrossSliceSelection.SLATSLICES)
&& this.spacing < SETTINGS.MIN_SPACING)
this.spacing = SETTINGS.MIN_SPACING;
}
//is plane not on a edge so move the construction lines
if (editing && this.type == CrossSliceSelection.PLANE) {
Vec2D pointOnPlan = GLOBAL.uiTools.getPointOnPlane(new Vec2D(
GLOBAL.uiTools.mouseX, GLOBAL.uiTools.mouseY), this.plane
.getPlane());
if (clicks == 1) {
SketchPath tempP = (SketchPath) this.path;
tempP.get(0).set(pointOnPlan);
}
if (clicks == 2) {
SketchPath tempP = (SketchPath) this.path;
tempP.get(1).set(pointOnPlan);
}
if (clicks == 3) {
this.end = 1;
editing = false;
this.plane.unselect();
this.path.unselect();
}
}
}
}