diff --git a/src/cad/fx/CSGNode.java b/src/cad/fx/CSGNode.java index 4885916e..2687e2cf 100644 --- a/src/cad/fx/CSGNode.java +++ b/src/cad/fx/CSGNode.java @@ -3,10 +3,12 @@ package cad.fx; import eu.mihosoft.vrl.v3d.CSG; import eu.mihosoft.vrl.v3d.Polygon; import javafx.scene.Group; +import javafx.scene.Node; import javafx.scene.Parent; import javafx.scene.shape.MeshView; import java.util.HashMap; +import java.util.List; import java.util.Map; public class CSGNode extends MeshView { @@ -17,6 +19,12 @@ public class CSGNode extends MeshView { super(mesh); this.context = context; setMaterial(Utils3D.DEFAULT_MATERIAL); + setOnMouseEntered(e -> { + context.highlightManger.selectExclusively(this); + }); + setOnMouseExited(e -> { + context.highlightManger.getSelection().clear(); + }); setOnMouseClicked(e -> { context.clickOnNode(this, e); }); @@ -25,6 +33,10 @@ public class CSGNode extends MeshView { private void highlight(Polygon poly) { System.out.println(poly); } + + private void select(Polygon poly) { + System.out.println(poly); + } public final Map sketches = new HashMap<>(); diff --git a/src/cad/fx/CadContext.java b/src/cad/fx/CadContext.java index fecfc5de..8ee8c437 100644 --- a/src/cad/fx/CadContext.java +++ b/src/cad/fx/CadContext.java @@ -1,9 +1,13 @@ package cad.fx; import cad.math.Vector; +import javafx.scene.Node; import javafx.scene.input.MouseEvent; import javafx.scene.input.PickResult; +import javafx.scene.paint.PhongMaterial; +import javafx.scene.shape.MeshView; +import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -11,8 +15,58 @@ public class CadContext { public Sketcher sketcher; public Selection selection; + public final SelectionManager selectionManger = new SelectionManager(); + public final SelectionManager highlightManger = new SelectionManager(); + + + class MaterialChangeListener implements SelectionManager.Listener { + + public final PhongMaterial onSelect; + public final PhongMaterial onDeselect; + private SelectionManager dependency; + + MaterialChangeListener(PhongMaterial onSelect, PhongMaterial onDeselect, SelectionManager dependency) { + this.onSelect = onSelect; + this.onDeselect = onDeselect; + this.dependency = dependency; + } + + public void added(List nodes) { + if (dependency != null) { + nodes = filter(nodes, dependency); + } + setMaterial(nodes, onSelect); + } + + public void removed(List nodes) { + if (dependency != null) { + nodes = filter(nodes, dependency); + } + setMaterial(nodes, onDeselect); + } + + private List filter(List nodes, SelectionManager dependency) { + nodes = new ArrayList<>(nodes); + nodes.removeAll(selectionManger.getSelection()); + return nodes; + } + } + + { + selectionManger.addListener(new MaterialChangeListener(Utils3D.SELECTED_MATERIAL, Utils3D.DEFAULT_MATERIAL, null)); + highlightManger.addListener(new MaterialChangeListener(Utils3D.HIGHLIGHTED_MATERIAL, Utils3D.DEFAULT_MATERIAL, selectionManger)); + } + + private void setMaterial(List nodes, PhongMaterial material) { + for (Node node : nodes) { + if (node instanceof MeshView) { + ((MeshView) node).setMaterial(material); + } + } + } public void clickOnNode(CSGNode csgNode, MouseEvent e) { + selectionManger.selectExclusively(csgNode); PickResult pickResult = e.getPickResult(); int face = pickResult.getIntersectedFace(); CSGMesh csgMesh = (CSGMesh) csgNode.getMesh(); @@ -64,8 +118,10 @@ public class CadContext { Surface surface = new Surface(sketch.owner.normal, polygon, Collections.emptyList()); List extruded = Surface.extrude(surface, dir); - sketch.drawLayer.getChildren().addAll(new CSGNode(Utils3D.getMesh(extruded), this)); // fixme + for (Surface s : extruded) { + sketch.drawLayer.getChildren().addAll(new CSGNode( Utils3D.getMesh(Collections.singletonList(s)), this)); // fixme + } // CSG pad = Extrude.points(dir, polygon); } } diff --git a/src/cad/fx/SelectionManager.java b/src/cad/fx/SelectionManager.java new file mode 100644 index 00000000..1c07e761 --- /dev/null +++ b/src/cad/fx/SelectionManager.java @@ -0,0 +1,66 @@ +package cad.fx; + +import com.sun.javafx.collections.TrackableObservableList; +import javafx.collections.ListChangeListener; +import javafx.collections.ObservableList; +import javafx.scene.Node; + +import java.util.ArrayList; +import java.util.List; + +public class SelectionManager { + + private final List listeners = new ArrayList<>(); + + public void addListener(Listener listener) { + listeners.add(listener); + } + + private final ObservableList selection = new TrackableObservableList() { + + protected void onChanged(ListChangeListener.Change c) { + while (c.next()) { + if (c.wasAdded()) { + List added = c.getAddedSubList(); + added.forEach((n) -> { + ObservableList styleClass = n.getStyleClass(); + if (!styleClass.contains("selected")) { + styleClass.add("selected"); + } + }); + fireSelected(added); + } else if (c.wasRemoved()) { + List removed = c.getRemoved(); + removed.forEach((n) -> n.getStyleClass().removeAll("selected")); + fireRemoved(removed); + } + } + } + }; + + private void fireRemoved(List removed) { + for (Listener l : listeners) { + l.removed(removed); + } + } + + private void fireSelected(List added) { + for (Listener l : listeners) { + l.added(added); + } + } + + public ObservableList getSelection() { + return selection; + } + + public interface Listener { + void added(List nodes); + void removed(List nodes); + } + + public void selectExclusively(Node node) { + selection.clear(); + selection.add(node); + } +} diff --git a/src/cad/fx/Utils3D.java b/src/cad/fx/Utils3D.java index 281fe586..fa778b9a 100644 --- a/src/cad/fx/Utils3D.java +++ b/src/cad/fx/Utils3D.java @@ -22,17 +22,26 @@ import java.util.List; public class Utils3D { public static final PhongMaterial DEFAULT_MATERIAL = new PhongMaterial(); + public static final PhongMaterial SELECTED_MATERIAL = new PhongMaterial(); + public static final PhongMaterial HIGHLIGHTED_MATERIAL = new PhongMaterial(); static { // DEFAULT_MATERIAL.setDiffuseColor(Color.LIGHTBLUE); // DEFAULT_MATERIAL.setSpecularColor(Color.WHITE); DEFAULT_MATERIAL.setDiffuseColor(Color.LIGHTSTEELBLUE); - DEFAULT_MATERIAL.setSpecularColor(Color.LIGHTBLUE); +// DEFAULT_MATERIAL.setSpecularColor(Color.LIGHTBLUE); + + SELECTED_MATERIAL.setDiffuseColor(Color.LIGHTSEAGREEN); +// SELECTED_MATERIAL.setSpecularColor(Color.SEAGREEN); //disable reflection + + HIGHLIGHTED_MATERIAL.setDiffuseColor(Color.LIGHTGOLDENRODYELLOW); +// HIGHLIGHTED_MATERIAL.setSpecularColor(Color.GOLD); // DEFAULT_MATERIAL.setDiffuseMap(new Image(Utils3D.class.getResource("tex.png").toExternalForm())); } + public static CSGMesh getMesh(List surfaces) { CSGMesh mesh = new CSGMesh(); @@ -45,46 +54,46 @@ public class Utils3D { for (Vector[] triangle : surface.getTriangles()) { - mesh.getPoints().addAll( - (float) triangle[0].x, - (float) triangle[0].y, - (float) triangle[0].z - ); + mesh.getPoints().addAll( + (float) triangle[0].x, + (float) triangle[0].y, + (float) triangle[0].z + ); - mesh.getTexCoords().addAll(0); // texture (not covered) - mesh.getTexCoords().addAll(0); + mesh.getTexCoords().addAll(0); // texture (not covered) + mesh.getTexCoords().addAll(0); mesh.getPoints().addAll( - (float) triangle[1].x, - (float) triangle[1].y, - (float) triangle[1].z + (float) triangle[1].x, + (float) triangle[1].y, + (float) triangle[1].z ); - mesh.getTexCoords().addAll(0); // texture (not covered) - mesh.getTexCoords().addAll(0); + mesh.getTexCoords().addAll(0); // texture (not covered) + mesh.getTexCoords().addAll(0); mesh.getPoints().addAll( - (float) triangle[2].x, - (float) triangle[2].y, - (float) triangle[2].z + (float) triangle[2].x, + (float) triangle[2].y, + (float) triangle[2].z ); - mesh.getTexCoords().addAll(0); // texture (not covered) - mesh.getTexCoords().addAll(0); + mesh.getTexCoords().addAll(0); // texture (not covered) + mesh.getTexCoords().addAll(0); - int counter = faceCounter * 3; - mesh.getFaces().addAll( - counter, // first vertex - 0, // texture (not covered) - counter + 1, // second vertex - 0, // texture (not covered) - counter + 2, // third vertex - 0 // texture (not covered) - ); - mesh.polygons.put(faceCounter, surface); - ++faceCounter; + int counter = faceCounter * 3; + mesh.getFaces().addAll( + counter, // first vertex + 0, // texture (not covered) + counter + 1, // second vertex + 0, // texture (not covered) + counter + 2, // third vertex + 0 // texture (not covered) + ); + mesh.polygons.put(faceCounter, surface); + ++faceCounter; } // end if #verts >= 3 @@ -105,27 +114,27 @@ public class Utils3D { TriangulationPoint firstVertex = p.points[0]; mesh.getPoints().addAll( - p.points[2].getXf(), - p.points[2].getYf(), - p.points[2].getZf() + p.points[2].getXf(), + p.points[2].getYf(), + p.points[2].getZf() ); mesh.getTexCoords().addAll(0); // texture (not covered) mesh.getTexCoords().addAll(0); mesh.getPoints().addAll( - p.points[1].getXf(), - p.points[1].getYf(), - p.points[1].getZf() + p.points[1].getXf(), + p.points[1].getYf(), + p.points[1].getZf() ); mesh.getTexCoords().addAll(0); // texture (not covered) mesh.getTexCoords().addAll(0); mesh.getPoints().addAll( - p.points[0].getXf(), - p.points[0].getYf(), - p.points[0].getZf() + p.points[0].getXf(), + p.points[0].getYf(), + p.points[0].getZf() ); mesh.getTexCoords().addAll(0); // texture (not covered) @@ -133,12 +142,12 @@ public class Utils3D { int counter = faceCounter * 3; mesh.getFaces().addAll( - counter, // first vertex - 0, // texture (not covered) - counter + 1, // second vertex - 0, // texture (not covered) - counter + 2, // third vertex - 0 // texture (not covered) + counter, // first vertex + 0, // texture (not covered) + counter + 1, // second vertex + 0, // texture (not covered) + counter + 2, // third vertex + 0 // texture (not covered) ); // mesh.polygons.put(faceCounter, p); ++faceCounter; @@ -148,15 +157,20 @@ public class Utils3D { return mesh; } + public static List createCube(double width) { + Surface square = createSquare(width); + return Surface.extrude(square, square.normal.scale(width)); + } + public static Surface createSquare(double width) { width /= 2; List shell = Arrays.asList( - new Vector(-width, -width), - new Vector(width, -width), - new Vector(width, width, 0), - new Vector(-width, width, 0) + new Vector(-width, -width), + new Vector(width, -width), + new Vector(width, width, 0), + new Vector(-width, width, 0) ); // width /= 3;