My application allows for the user to click on the background on which a scene graph is drawn.
The location of the point, where the user clicks needs to be extracted. For this, I made use of
a suggestion given on this forum - create a transparent quadrilateral geometry and add it to the
scene graph. In this case, PickResult gives the location clicked.
This worked for me in some of my code. But I reproduced the same working code in the following
example and it does not work. I do not know why.
In this code, the application shows two curves, one with points and the other without. The user (shift left button)
clicks on a vertex of a curve (yellow dots) and then clicks on the background at a location. Both the curves are
reshaped based on these two points. This is an example of a more general problem - given a complex set of geometric
objects, if an operation is performed on an object, changes should be computed and rendered for the other objects as well.
In order to do this I change the scene graph and update the geometry factories and reload the scene graph components.
For this reason, I do not use PointSets as shown in the tutorials. (It would be nice if the ToolContext can provide the
Scene Graph Component on which the user performs an action).
Desired Behavior:
"perform" method conditionally chooses two segments of code. The first segment is selected for the first click and the second
segment is selected for the second click. In the second segment, both the clicked points are collected and the scene graph is
updated.
Problem Behavior:
The control is not entering the second segment. The reason seems to be PickResult always set to null for the second click (click on the
background). I do not know why. Can you help!
Code: Select all
public class PickClickTest {
// private ConsolePrinter cPrinter;
private SceneGraphComponent sceneGraph;
private static DefaultGeometryShader dgs;
private static DefaultLineShader dls;
private static DefaultPointShader dpts;
private static RenderingHintsShader rhs;
private double[][] Pw;
private double[][] curvePoints;
private SceneGraphComponent curve;
private SceneGraphComponent controlPolygon;
private double[] startPoint;
private double[] endPoint;
private boolean mouseClicked = false;
private int performIndex = 0;
private int pointIndex;
public static void main(String[] args) {
PickClickTest test = new PickClickTest();
}
public PickClickTest() {
sceneGraph = createSceneGraph();
setUpCoordinateSystem(sceneGraph);
setUpTool(sceneGraph);
JRViewer.display(sceneGraph);
}
private SceneGraphComponent createSceneGraph() {
Pw = new double[6][];
Pw[0] = new double[] { 0.0, 0.0, 0.0 };
Pw[1] = new double[] { 3.0, 25.0, 0.0 };
Pw[2] = new double[] { 13.0, 22.0, 0.0 };
Pw[3] = new double[] { 18.0, 10.0, 0.0 };
Pw[4] = new double[] { 28.0, 13.0, 0.0 };
Pw[5] = new double[] { 32.0, 45.0, 0.0 };
curvePoints = new double[][] { { 0.0, 0.0, 0.0 }, { 3.0, 5.0, 0.0 },
{ 6.0, 20.0, 0.0 }, { 9.0, 40.0, 0.0 }, { 12.0, 30.0, 0.0 },
{ 15.0, 15.0, 0.0 }, { 18.0, 1.0, 0.0 }, { 21.0, 7.0, 0.0 },
{ 24.0, 16.0, 0.0 }, { 27.0, 23.0, 0.0 }, { 30.0, 36.0, 0.0 },
{ 33.0, 44.0, 0.0 } };
curve = setupCurve(curvePoints);
controlPolygon = setupControlPolygon(Pw);
curve.addChild(controlPolygon);
controlPolygon.addChild(setUpBackgroundScene(curvePoints, Pw));
return curve;
}
private SceneGraphComponent setupControlPolygon(double[][] pw2) {
SceneGraphComponent cPolygon = SceneGraphUtility
.createFullSceneGraphComponent("Curve");
Appearance ap = new Appearance();
setupSceneComponentGeometry(pw2, cPolygon);
setupControlPolygonAppearance(ap, Color.GREEN, cPolygon);
return cPolygon;
}
private SceneGraphComponent setupCurve(double[][] curvePoints) {
SceneGraphComponent sgc = SceneGraphUtility
.createFullSceneGraphComponent("Curve");
Appearance ap = new Appearance();
setupSceneComponentGeometry(curvePoints, sgc);
setupCurveAppearance(ap, Color.BLUE, sgc);
return sgc;
}
private void setupCurveAppearance(Appearance ap, Color color,
SceneGraphComponent sgc) {
dgs = ShaderUtility.createDefaultGeometryShader(ap, true);
dgs.setShowFaces(false);
dgs.setShowLines(true);
dgs.setShowPoints(false);
dls = (DefaultLineShader) dgs.createLineShader("default");
dls.setDiffuseColor(color);
sgc.setAppearance(ap);
}
public SceneGraphComponent setUpBackgroundScene(double[][] curvePoints,
double[][] controlPoints) {
SceneGraphComponent backgroundSGC = SceneGraphUtility
.createFullSceneGraphComponent("Background");
double width = 50;
double height = 50;
double[] corners = { 0, 0, 0, width, 0, 0, width, height, 0, 0, height,
0 };
Appearance ap = backgroundSGC.getAppearance();
ap.setAttribute("transparencyEnabled", true);
ap.setAttribute("transparency", 1.0);
MatrixBuilder.euclidean().translate(0, 0, -.001)
.assignTo(backgroundSGC);
backgroundSGC.setGeometry(Primitives.texturedQuadrilateral(corners));
return backgroundSGC;
}
private void setupSceneComponentGeometry(double[][] pts,
SceneGraphComponent sgc) {
IndexedLineSetFactory ilsf = new IndexedLineSetFactory();
double[][] vertices = pts;
int[][] edgeIndices = createEdgeIndices(vertices);
ilsf.setVertexCount(vertices.length);
ilsf.setVertexCoordinates(vertices);
ilsf.setEdgeCount(edgeIndices.length);
ilsf.setEdgeIndices(edgeIndices);
ilsf.update();
sgc.setGeometry(ilsf.getIndexedLineSet());
}
private void setUpTool(SceneGraphComponent sgc) {
mouseClicked = false;
sgc.addTool(new AbstractTool() {
{
addCurrentSlot(InputSlot.SHIFT_LEFT_BUTTON, "add a new point");
}
public void perform(ToolContext tc) {
System.out.println("Entering perform method");
System.out.println("Perform Index: " + performIndex);
// if (performIndex == 0)
performIndex++;
if (!tc.getAxisState(InputSlot.SHIFT_LEFT_BUTTON).isPressed()) {
System.out.println("AxisState is not shift left button");
return;
}
// only show interest in real picks
PickResult pr = tc.getCurrentPick();
// could also reject all picks that don't end at the
// backgroundSGC node
if (pr == null) {
System.out.println("PickResult null for performIndex: "
+ performIndex);
return;
}
pointIndex = pr.getIndex();
System.out.println("Point index: " + pointIndex);
System.out.println("Mouseclicked: " + mouseClicked);
if (!mouseClicked) {
startPoint = pr.getObjectCoordinates();
startPoint = new double[] {
roundThreeDecimals(startPoint[0]),
roundThreeDecimals(startPoint[1]),
roundThreeDecimals(startPoint[2]) };
// int insertionPoint = lineIndex;
// points.add(new Point3D(startPoint));
System.out
.println("Start Point is: [" + startPoint[0] + ", "
+ startPoint[1] + ", " + startPoint[2]
+ "]");
mouseClicked = true;
} else {
System.out.println("Else condition entered: ");
performIndex = 0;
endPoint = pr.getObjectCoordinates();
endPoint = new double[] { roundThreeDecimals(endPoint[0]),
roundThreeDecimals(endPoint[1]),
roundThreeDecimals(endPoint[2]) };
Pw[pointIndex] = endPoint;
updateSGC_withNewGeometry();
}
}
});
}
protected void updateSGC_withNewGeometry() {
curvePoints[pointIndex+1] = endPoint;
setupSceneComponentGeometry(curvePoints, curve);
setupSceneComponentGeometry(Pw, controlPolygon);
setUpCoordinateSystem(sceneGraph);
}
public void setUpCoordinateSystem(SceneGraphComponent component) {
// create coordinate system
double axisScale = 5.0;
final CoordinateSystemFactory coords = new CoordinateSystemFactory(
component, axisScale);
// SET PROPERTIES:
Font font = new Font("TimesRoman", Font.PLAIN, 40);
coords.setAxisScale(axisScale);
coords.setLabelScale(0.02);
// coords.showBoxArrows(true);
coords.showAxesArrows(true);
coords.showLabels(true);
// coords.setColor(Color.RED);
// coords.setGridColor(Color.GRAY);
coords.setLabelColor(Color.BLACK);
coords.setLabelFont(font);
coords.setColor(Color.BLUE);
// display axes/box/grid
coords.showAxes(true);
// coords.showBox(true);
coords.showGrid(true);
// beautify box
coords.beautify(true);
}
private void setupControlPolygonAppearance(Appearance ap, Color color,
SceneGraphComponent sgc) {
dgs = ShaderUtility.createDefaultGeometryShader(ap, true);
dgs.setShowFaces(false);
dgs.setShowLines(true);
dgs.setShowPoints(true);
dls = (DefaultLineShader) dgs.createLineShader("default");
dls.setDiffuseColor(color);
dls.setLineStipple(true);
dls.setLineWidth(2.0);
dls.setLineFactor(2); // scales the dots and dashes
dpts = (DefaultPointShader) dgs.createPointShader("default");
dpts.setDiffuseColor(Color.yellow);
dpts.setPointRadius(.4);
rhs = ShaderUtility.createDefaultRenderingHintsShader(ap, true);
rhs.setTransparencyEnabled(true);
rhs.setOpaqueTubesAndSpheres(true);
sgc.setAppearance(ap);
}
public int[][] createEdgeIndices(double[][] points) {
int[][] edges = new int[points.length - 1][2];
for (int i = 0; i < points.length - 1; i++) {
edges[i][0] = i;
edges[i][1] = i + 1;
}
return edges;
}
public double roundThreeDecimals(double d) {
DecimalFormat threeDForm = new DecimalFormat("#.###");
return Double.valueOf(threeDForm.format(d));
}
}
Thanks,
Karuna