X-Git-Url: https://gerrit.simantics.org/r/gitweb?a=blobdiff_plain;f=org.simantics.g3d%2Fsrc%2Forg%2Fsimantics%2Fproconf%2Fg3d%2Fbase%2FConstraintDetector.java;fp=org.simantics.g3d%2Fsrc%2Forg%2Fsimantics%2Fproconf%2Fg3d%2Fbase%2FConstraintDetector.java;h=d50943cbd390847b473e8f72b34b8462773bb403;hb=10f144a2bb2d7bec98b812b83acecb333fd098ea;hp=0000000000000000000000000000000000000000;hpb=3055b543aa5afc0cca4bb3b341704e7c5103fa6a;p=simantics%2F3d.git diff --git a/org.simantics.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java b/org.simantics.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java new file mode 100644 index 00000000..d50943cb --- /dev/null +++ b/org.simantics.g3d/src/org/simantics/proconf/g3d/base/ConstraintDetector.java @@ -0,0 +1,442 @@ +/******************************************************************************* + * Copyright (c) 2007- VTT Technical Research Centre of Finland. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * VTT Technical Research Centre of Finland - initial API and implementation + *******************************************************************************/ +package org.simantics.proconf.g3d.base; + +import java.util.ArrayList; +import java.util.List; + +import javax.vecmath.Point3d; +import javax.vecmath.Vector3d; + +import org.simantics.db.Graph; +import org.simantics.db.GraphRequestWithResult; +import org.simantics.db.Resource; +import org.simantics.db.adaption.AdaptionException; +import org.simantics.proconf.g3d.Resources; +import org.simantics.utils.ui.ErrorLogger; + +import com.jme.renderer.ColorRGBA; +import com.jme.scene.Geometry; +import com.jme.scene.Line; +import com.jme.scene.state.MaterialState; +import com.jme.util.geom.BufferUtils; + +public class ConstraintDetector { + + private static final int X = 0; + private static final int Y = 1; + private static final int Z = 2; + + + private ThreeDimensionalEditorBase editor; + //private G3DNode constraintReference = null; + private Resource constraintReference = null; + private ArrayList constraintPoints = new ArrayList(); + private ArrayList constraintDirections = new ArrayList(); + private MaterialState ms; + + private ColorRGBA xColor = new ColorRGBA(1.f,0.f,0.f,1.f); + private ColorRGBA yColor = new ColorRGBA(0.f,1.f,0.f,1.f); + private ColorRGBA zColor = new ColorRGBA(0.f,0.f,1.f,1.f); + + + public ConstraintDetector(ThreeDimensionalEditorBase editor) { + this.editor = editor; + ms = editor.getRenderingComponent().getDisplaySystem().getRenderer().createMaterialState(); + ms.setEmissive(new ColorRGBA(1.f,1.f,1.f,1.f)); + ms.setColorMaterial(MaterialState.CM_EMISSIVE); + } + + + public void clearConstraints() { + //System.out.println("ConstraintDetector.clearConstraints()"); + constraintPoints.clear(); + constraintDirections.clear(); + } + + private void updateConstraints() { + clearConstraints(); + if (constraintReference == null) + return; + GraphRequestWithResult request = new GraphRequestWithResult() { + @Override + public Constraint performWithResult(Graph g) throws Exception { + try { + return g.adapt(constraintReference, Resources.g3dResource.HasConstraints); + } catch (AdaptionException e) { + ErrorLogger.defaultLogWarning("Cannot add constraint", e); + return null; + } + } + }; + editor.getSession().syncRead(request); + Constraint c = request.getResult(); + if (c == null) + return; + constraintPoints.addAll(c.points); + constraintDirections.addAll(c.dirs); + } + + + public ArrayList getConstraintPoints() { + return constraintPoints; + } + + public ArrayList getConstraintDirections() { + return constraintDirections; + } + + public void updateConstraintReference() { + + Resource interactive = null; + if (editor.getSelectionAdapter().getHighlightSelection().size() > 0) { + interactive = editor.getSelectionAdapter().getInteractiveSelectedObjects().iterator().next().getResource(); + if (constraintReference == null) { + constraintReference = interactive; + updateConstraints(); + } else if (!constraintReference.getResource().equals(interactive.getResource())) { + constraintReference = interactive; + updateConstraints(); + } + } else { + constraintReference = null; + updateConstraints(); + } + + } + + public void addContraintPoint(Point3d p) { + //System.out.println("ConstraintDetector.addConstraintPoint() " + p); + constraintPoints.add(p); + } + + public void addContraintDirection(Vector3d v) { + //System.out.println("ConstraintDetector.addConstraintDirection() " + v); + constraintDirections.add(v); + } + + private double snapAngle = 0.1; + private String snapString = ""; + + private ArrayList constraintHighlights = new ArrayList(); + + public Point3d getSnappedPoint(Vector3d pickPoint, Vector3d pickDir, Vector3d requestedPoint) { + + + Vector3d snappedPoint = new Vector3d(); + Vector3d t = new Vector3d(); + Point3d currentPoint = null; + // TODO : snap to closest angle + for (Vector3d constraintDir : constraintDirections) { + + MathTools.intersectStraightStraight(pickPoint,pickDir, requestedPoint, constraintDir, t, snappedPoint); + t.sub(snappedPoint); + if (t.lengthSquared() < snapAngle) { + + snapString += "Angle snap "; + currentPoint = new Point3d(snappedPoint); + break; + } + } + if (currentPoint != null) { + Vector3d dir = new Vector3d(currentPoint); + dir.sub(requestedPoint); + Point3d p = getPointSnap(requestedPoint, dir); + if (p != null) + currentPoint = p; + } else { + List distances = new ArrayList(); + List snapPoints = new ArrayList(); + List snapStrings = new ArrayList(); + List snapColors = new ArrayList(); + for (Point3d constraintPoint : constraintPoints) { + distances.clear(); + snapPoints.clear(); + snapStrings.clear(); + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(1.0, 0.0, 0.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + double distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point x-snap "); + snapColors.add(xColor); + } + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 1.0, 0.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point y-snap "); + snapColors.add(yColor); + } + MathTools.intersectStraightStraight(new Vector3d(constraintPoint), new Vector3d(0.0, 0.0, 1.0), + pickPoint, pickDir, snappedPoint, t); + t.sub(snappedPoint); + distance = t.lengthSquared(); + if (distance < snapAngle) { + distances.add(distance); + snapPoints.add(new Point3d(snappedPoint)); + snapStrings.add("Point z-snap "); + snapColors.add(zColor); + + } + if (distances.size() > 0) { + if (distances.size() > 1) { + // more than one axes snape + Vector3d ref = MathTools.closestPointOnStraight(constraintPoint, new Point3d(pickPoint), pickDir); + ref.sub(constraintPoint); + distance = ref.lengthSquared(); + if (distance < snapAngle) { + // we are close enought to point, so we'll just snap there + currentPoint = new Point3d(constraintPoint); + snapString += "Point snap "; + } else { + // select the closest of axes snap to + int min = 0; + for (int i = 1; i < distances.size(); i++) { + if (distances.get(i) < distances.get(min)) + min = i; + } + currentPoint = snapPoints.get(min); + addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(min)); + snapString += snapStrings.get(min); + } + } else { + // only one of the axes snaps + currentPoint = snapPoints.get(0); + addConstrainLineHighlight(currentPoint, constraintPoint,snapColors.get(0)); + snapString += snapStrings.get(0); + } + break; + } + } + } + return currentPoint; + + } + + public void clearConstraintHighlights() { + snapString = ""; + + for (Geometry s : constraintHighlights) + s.removeFromParent(); + + constraintHighlights.clear(); + } + + private void addConstrainLineHighlight(Point3d p1, Point3d p2, ColorRGBA color) { + + float coord[] = new float[6]; + ColorRGBA colors[] = new ColorRGBA[2]; + colors[0] = color; + colors[1] = color; + coord[0] = (float)p1.x; + coord[1] = (float)p1.y; + coord[2] = (float)p1.z; + coord[3] = (float)p2.x; + coord[4] = (float)p2.y; + coord[5] = (float)p2.z; + Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null); + editor.getRenderingComponent().getNoShadowRoot().attachChild(shape); + shape.setRenderState(ms); + constraintHighlights.add(shape); + } + + private void addConstrainPlaneHighlight(Point3d p1, Point3d p2, int axis) { + + float coord[] = new float[9]; + ColorRGBA colors[] = new ColorRGBA[3]; + coord[0] = (float)p1.x; + coord[1] = (float)p1.y; + coord[2] = (float)p1.z; + switch (axis) { + case X: + coord[3] = (float)p1.x; + coord[4] = (float)p1.y; + coord[5] = (float)p2.z; + colors[0] = colors[1] = colors[2] = xColor; + break; + case Y: + coord[3] = (float)p1.x; + coord[4] = (float)p1.y; + coord[5] = (float)p2.z; + colors[0] = colors[1] = colors[2] = yColor; + break; + case Z: + coord[3] = (float)p1.x; + coord[4] = (float)p2.y; + coord[5] = (float)p2.z; + colors[0] = colors[1] = colors[2] = zColor; + break; + + } + coord[6] = (float)p2.x; + coord[7] = (float)p2.y; + coord[8] = (float)p2.z; + Line shape = new Line("",BufferUtils.createFloatBuffer(coord),null,BufferUtils.createFloatBuffer(colors),null); + shape.setMode(Line.CONNECTED); + editor.getRenderingComponent().getNoShadowRoot().attachChild(shape); + shape.setRenderState(ms); + constraintHighlights.add(shape); + } + + /** + * Snaps position to axis-aligned planes defined by constraint points + * Form of position is p+v, meaning that the position that is snapped is requestedPoint + requestedDir + * @param requestedPoint one part of the position to be snapped + * @param requestedDir second part of the position to be snapped and direction that the position is allowed to move + * @return + */ + public Point3d getPointSnap(Vector3d requestedPoint, Vector3d requestedDir) { + + Vector3d snappedPoint = new Vector3d(); + Point3d currentPoint = null; + double u[] = new double[1]; + List p1s = new ArrayList(); + List p2s = new ArrayList(); + List axes = new ArrayList(); + + for (Point3d constraintPoint : constraintPoints) { + boolean snap = false; + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(X), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane x-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,X); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(X); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Y), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane y-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,Y); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(Y); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), getAxialVector(Z), snappedPoint,u) && Math.abs(1.0 - u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + //snapString += "Point/Plane z-snap "; + snap = true; + //addConstrainPlaneHighlight(constraintPoint, currentPoint,Z); + p1s.add(constraintPoint); + p2s.add(currentPoint); + axes.add(Z); + } + if (snap) + break; + } + if (p1s.size() == 0) + return null; + if (p1s.size() == 1) { + snapString += "Point/Plane "; + switch (axes.get(0)) { + case X: + snapString += "x"; + break; + case Y: + snapString += "y"; + break; + case Z: + snapString += "z"; + break; + } + snapString += "-snap "; + addConstrainPlaneHighlight(p1s.get(0), p2s.get(0),axes.get(0)); + return currentPoint; + } else if (p1s.size() == 3){ + // all axial planes are intersecting, snapping point must be the constraint point + // all constraint points are the same, so just pick the first in the list + snapString += "Point/Point "; + return p1s.get(0); + } else { + Vector3d dir = new Vector3d(); + dir.cross(getAxialVector(axes.get(0)), getAxialVector(axes.get(1))); + currentPoint = new Point3d(MathTools.closestPointOnStraight(currentPoint, p1s.get(0), dir)); + addConstrainLineHighlight(p1s.get(0), currentPoint, xColor); + snapString += "Point/Line "; + return currentPoint; + } + + } + + private Vector3d getAxialVector(int axis) { + switch (axis) { + case X: + return new Vector3d(1.0,0.0,0.0); + case Y: + return new Vector3d(0.0,1.0,0.0); + case Z: + return new Vector3d(0.0,0.0,1.0); + } + throw new RuntimeException("Unknown axis " + axis); + } + + /** + * Snaps the position to axis-aligned planes defined by constraint points + * @param requestedPoint point that is snapped + * @param requestedDir direction that point is allowed to move + * @return + */ + + public Point3d getPointSnap2(Vector3d requestedPoint, Vector3d requestedDir) { + + Vector3d snappedPoint = new Vector3d(); + Point3d currentPoint = null; + double u[] = new double[1]; + //System.out.println(requestedPoint + " " + requestedDir); + for (Point3d constraintPoint : constraintPoints) { + boolean snap = false; + //System.out.print(constraintPoint + " "); + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(1.0,0.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane x-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,X); + //System.out.print(" x " + u[0]); + } + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,1.0,0.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane y-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,Y); + //System.out.print(" y " + u[0]); + } + + + if (MathTools.intersectStraightPlane(requestedPoint, requestedDir, new Vector3d(constraintPoint), new Vector3d(0.0,0.0,1.0), snappedPoint,u) && Math.abs(u[0]) < snapAngle) { + currentPoint = new Point3d(snappedPoint); + snapString += "Point/Plane z-snap "; + snap = true; + addConstrainPlaneHighlight(constraintPoint, currentPoint,Z); + //System.out.print(" z " + u[0]); + } + //System.out.println(); + if (snap) + break; + } + return currentPoint; + } + + public String getSnapString() { + return snapString; + } +} \ No newline at end of file