/** * Simple algorithm to add or remove an edge from the selection Ideas: 1. Use one shape per quad * => easy, but can become very fast too big to fit in memory. => pb: flicker when adding / * removing because the scene is detached 2. Use only one shape, modify geometry TODO: pre-create * an empty shape to avoid initial flicker * * @param on * @param p * @param u * @param v * @param groupIdx2 */ protected void toggleSelectedEdge(boolean on, SelectionEdge se) { if (on) { // add the given edge to the list if (edgeSelection.contains(se)) return; // already in edgeSelection.add(se); } else { // remove the given edge from the list if (!edgeSelection.contains(se)) return; // not present edgeSelection.remove(se); if (edgeSelection.size() == 0) { LineArray la = (LineArray) edgeSelectionShape.getGeometry(); la.setValidVertexCount(0); return; } } // Use in-memory arrays instead of NIO because edgeSelection should not // be too big // => faster LineArray la = new LineArray( edgeSelection.size() * 2, GeometryArray.COORDINATES | GeometryArray.COLOR_3 | GeometryArray.BY_REFERENCE); double[] coords = new double[edgeSelection.size() * 2 * 3]; float[] colors = new float[edgeSelection.size() * 2 * 3]; for (int i = 0; i < coords.length; i += 6) { SelectionEdge edge = edgeSelection.get(i / 6); edge.updateCoords(grid, coords, i); edge.updateColors(colors, i); } la.setCoordRefDouble(coords); la.setColorRefFloat(colors); la.setCapability(GeometryArray.ALLOW_COUNT_WRITE); // update edgeSelection Shape with the new edgeSelection list if (edgeSelectionShape == null) { Appearance a = new Appearance(); // PolygonAttributes pa = new // PolygonAttributes(PolygonAttributes.POLYGON_LINE, // PolygonAttributes.CULL_NONE, 0); // pa.setPolygonOffset(1); // above edges // pa.setPolygonOffsetFactor(1); LineAttributes lat = new LineAttributes(); lat.setLineWidth(2.0f); lat.setLineAntialiasingEnable(true); a.setLineAttributes(lat); // a.setPolygonAttributes(pa); edgeSelectionShape = new Shape3D(la, a); edgeSelectionShape.setUserData(this); edgeSelectionShape.setPickable(false); edgeSelectionShape.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE); edgeSelectionShape.setCapability(Shape3D.ALLOW_GEOMETRY_READ); BranchGroup bg = new BranchGroup(); bg.addChild(edgeSelectionShape); addChild(bg); } else edgeSelectionShape.setGeometry(la); }
/** * Simple algorithm to add or remove a quad from the selection Ideas: 1. Use one shape per quad => * easy, but can become very fast too big to fit in memory. => pb: flicker when adding / removing * because the scene is detached 2. Use only one shape, modify geometry TODO: pre-create an empty * shape to avoid initial flicker * * @param on * @param p * @param u * @param v * @param groupIdx2 */ protected void toggleSelectedQuad(boolean on, SelectionQuad sq) { LOGGER.finest("on=" + on + " selectionQuad=" + sq); if (on) { // add the given quad to the list if (selection.contains(sq)) return; // already in selection.add(sq); } else { // remove the given quad from the list if (!selection.contains(sq)) return; // not present selection.remove(sq); if (selection.size() == 0) { QuadArray qa = (QuadArray) selectionShape.getGeometry(); qa.setValidVertexCount(0); return; } } // Use in-memory arrays instead of NIO because selection should not be // too big // => faster QuadArray qa = new QuadArray( selection.size() * 4, GeometryArray.COORDINATES | GeometryArray.COLOR_3 | GeometryArray.BY_REFERENCE); float[] coords = new float[selection.size() * 4 * 3]; float[] colors = new float[selection.size() * 4 * 3]; for (int i = 0; i < coords.length; i += 12) { SelectionQuad quad = selection.get(i / 12); quad.updateCoords(grid, coords, i); quad.updateColors(colors, i); } qa.setCoordRefFloat(coords); qa.setColorRefFloat(colors); qa.setCapability(GeometryArray.ALLOW_COUNT_WRITE); // update selection Shape with the new selection list if (selectionShape == null) { Appearance a = new Appearance(); PolygonAttributes pa = new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0); pa.setPolygonOffset(0.5f); // between faces and edges pa.setPolygonOffsetFactor(0.5f); a.setPolygonAttributes(pa); selectionShape = new Shape3D(qa, a); selectionShape.setUserData(this); selectionShape.setPickable(false); selectionShape.setCapability(Shape3D.ALLOW_GEOMETRY_WRITE); selectionShape.setCapability(Shape3D.ALLOW_GEOMETRY_READ); BranchGroup bg = new BranchGroup(); bg.addChild(selectionShape); addChild(bg); } else selectionShape.setGeometry(qa); }
protected void makeWires() { Wire[] wires = createWireList(); if (wires.length == 0) return; FloatBuffer nioWires = ByteBuffer.allocateDirect(wires.length * 2 * 3 * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); for (int i = 0; i < wires.length; i++) { nioWires.put(wires[i].getCoordinates(grid)); } // Create edge shapes directly, don't make it appear in graph LineArray la = new NioLineArray(wires.length * 2, GeometryArray.COORDINATES | GeometryArray.COLOR_3); la.setCoordRefBuffer(new J3DBuffer(nioWires)); int colSize = wires.length * 2 * 3; FloatBuffer nioWireColors = ByteBuffer.allocateDirect(colSize * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); float[] colors = getColorForOrder(-2, 0); for (int i = 0; i < colSize; i += 3) nioWireColors.put(colors); la.setColorRefBuffer(new J3DBuffer(nioWireColors)); la.setUserData(new int[] {-2, 0}); Appearance a = new Appearance(); // PolygonAttributes pa = new // PolygonAttributes(PolygonAttributes.POLYGON_LINE, // PolygonAttributes.CULL_NONE, 0); // pa.setPolygonOffset(2); // pa.setPolygonOffsetFactor(2); // a.setPolygonAttributes(pa); /* * LineAttributes lat = new LineAttributes(); lat.setLineWidth(2.0f); * a.setLineAttributes(lat); */ Shape3D s3d = new Shape3D(la, a); PickTool.setCapabilities(s3d, PickTool.INTERSECT_FULL); s3d.setCapability(Shape3D.ALLOW_APPEARANCE_READ); s3d.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); s3d.setCapability(Node.ALLOW_PICKABLE_READ); s3d.setCapability(Node.ALLOW_PICKABLE_WRITE); s3d.setPickable(true); // by default, can be changed with actions s3d.setUserData(this); // this object will handle edges addChild(s3d); allEdgeShapes.add(s3d); }
/* * (non-Javadoc) * * @see syn3d.base.ActiveNode#highlight(boolean, java.lang.Object) */ public void highlight(boolean on, Object parameter) { System.out.println("Total memory: " + Runtime.getRuntime().totalMemory()); System.out.println("Free memory: " + Runtime.getRuntime().freeMemory()); System.out.println(System.currentTimeMillis() + " starting highlight with " + parameter); if (parameter instanceof PickResult) { PickResult result = (PickResult) parameter; result.setFirstIntersectOnly(true); PickIntersection pi = result.getIntersection(0); // indices of the picked quad // Indices are set to vertex indices, as this is not an Index // Geometry object // => easy to find the plate index from this int[] idx = pi.getPrimitiveCoordinateIndices(); int plateNum = idx[0] / 4; Plate p = plates[plateNum]; Point3d point3d = pi.getPointCoordinates(); point3d.get(point); FloatBuffer coords = (FloatBuffer) ((NioQuadArray) (shape.getGeometry())).getCoordRefBuffer().getBuffer(); for (int i = 0; i < idx.length; ++i) { coords.position(idx[i] * 3); coords.get(vertices[i]); } int d1 = 0, d2 = 0; if (p instanceof PlateX) { d1 = 1; d2 = 2; } else if (p instanceof PlateY) { d1 = 0; d2 = 2; } else if (p instanceof PlateZ) { d1 = 0; d2 = 1; } int u = (int) Math.floor( (point[d1] - vertices[0][d1]) * (p.max1 - p.min1) / (vertices[3][d1] - vertices[0][d1])); int v = (int) Math.floor( (point[d2] - vertices[0][d2]) * (p.max2 - p.min2) / (vertices[1][d2] - vertices[0][d2])); int quadIdx = v * (p.max1 - p.min1) + u; u += p.min1; v += p.min2; System.out.println( (on ? "" : "de") + "selected quad " + quadIdx + " in plate " + plateNum + " in group "); System.out.println("Grid positions for the quad (x,y,z) indices:"); int[] pos = p.getXYZGridIndices(u, v); System.out.println("vertex1 = (" + pos[0] + ", " + pos[1] + ", " + pos[2] + ")"); pos = p.getXYZGridIndices(u, v + 1); System.out.println("vertex2 = (" + pos[0] + ", " + pos[1] + ", " + pos[2] + ")"); pos = p.getXYZGridIndices(u + 1, v + 1); System.out.println("vertex3 = (" + pos[0] + ", " + pos[1] + ", " + pos[2] + ")"); pos = p.getXYZGridIndices(u + 1, v); System.out.println("vertex4 = (" + pos[0] + ", " + pos[1] + ", " + pos[2] + ")"); float[] color = getColorForOrder(groupIdx, on ? 1 : 0); for (int i = 0; i < idx.length; ++i) { colors.position(idx[i] * 3); colors.put(color); } toggleSelectedQuad(on, new SelectionQuad(p, u, v, groupIdx)); // Use event propagation, but don't call // setAppearanceForHighlight FloatBuffer tmp = colors; colors = null; colors = tmp; } System.out.println(System.currentTimeMillis() + " end of highlight"); }
public BehindShape(Shape3D s3d, Plate[] plates, int g) { this.shape = s3d; this.groupIdx = g; colors = (FloatBuffer) ((NioQuadArray) (shape.getGeometry())).getColorRefBuffer().getBuffer(); this.plates = plates; }
protected void makeGroups() { int totalQuads = 0; int totalInternalEdges = 0; int totalExternalEdges = 0; // loop over each group // loop over each group int[] groupID = provider.getDomainIDs(); for (int g = 0; g < groupID.length; ++g) { LOGGER.finest("generating java3d tree for group number " + groupID[g]); // Set of EdgeLine objects. Overlapping edges on the same line are // merged together HashMap<EdgeLine, EdgeLine> externalEdges = new HashMap<EdgeLine, EdgeLine>(); // Same trick for internal edges. HashMap<EdgeLine, EdgeLine> internalEdges = new HashMap<EdgeLine, EdgeLine>(); FDDomain fdDomain = (FDDomain) provider.getDomain(groupID[g]); baseColor.put(new Integer(g), fdDomain.getColor()); Plate[] plates = domainToPlates(fdDomain); if (plates.length == 0) continue; // Create plates for this group FloatBuffer nioCoords = ByteBuffer.allocateDirect(plates.length * 4 * 3 * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); FloatBuffer nioColors = ByteBuffer.allocateDirect(plates.length * 4 * 3 * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer(); float[] baseColor = getColorForOrder(g, 0); // System.out.println(baseColor[0]+" "+baseColor[1]+" "+baseColor[2]); for (int np = 0; np < plates.length; ++np) { Plate p = plates[np]; // put coordinates nioCoords.put(p.getCoordinates(grid)); // put colors for the 4 vertices nioColors.put(baseColor); nioColors.put(baseColor); nioColors.put(baseColor); nioColors.put(baseColor); // Merge external edges addEdge(externalEdges, getLine(p, 2, p.min1), p.min2, p.max2); addEdge(externalEdges, getLine(p, 2, p.max1), p.min2, p.max2); addEdge(externalEdges, getLine(p, 1, p.min2), p.min1, p.max1); addEdge(externalEdges, getLine(p, 1, p.max2), p.min1, p.max1); // Merge internal edges for (int i = p.min1 + 1; i < p.max1; ++i) addEdge(internalEdges, getLine(p, 2, i), p.min2, p.max2); for (int j = p.min2 + 1; j < p.max2; ++j) addEdge(internalEdges, getLine(p, 1, j), p.min1, p.max1); } // use by reference array of colors => fast to change! QuadArray qa = new NioQuadArray(plates.length * 4, GeometryArray.COORDINATES | GeometryArray.COLOR_3); qa.setCoordRefBuffer(new J3DBuffer(nioCoords)); qa.setColorRefBuffer(new J3DBuffer(nioColors)); qa.setCapability(GeometryArray.ALLOW_COLOR_WRITE); qa.setCapabilityIsFrequent(GeometryArray.ALLOW_COLOR_WRITE); Appearance a = new Appearance(); PolygonAttributes pa = new PolygonAttributes(PolygonAttributes.POLYGON_FILL, PolygonAttributes.CULL_NONE, 0); pa.setPolygonOffset(1); pa.setPolygonOffsetFactor(1); a.setPolygonAttributes(pa); Shape3D s3d = new Shape3D(qa, a); PickTool.setCapabilities(s3d, PickTool.INTERSECT_FULL); s3d.setCapability(Shape3D.ALLOW_APPEARANCE_READ); s3d.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); s3d.setCapability(Node.ALLOW_PICKABLE_READ); s3d.setCapability(Node.ALLOW_PICKABLE_WRITE); s3d.setPickable(true); s3d.setUserData(new BehindShape(s3d, plates, g)); this.addChild(s3d); // Create edge shapes directly, don't make them appear in graph int nInternalEdges = 0; for (Iterator<EdgeLine> it = internalEdges.keySet().iterator(); it.hasNext(); ) { EdgeLine el = it.next(); nInternalEdges += el.getNumberOfEdges(); } if (nInternalEdges > 0) { DoubleBuffer nioInternalEdges = ByteBuffer.allocateDirect(nInternalEdges * 2 * 3 * 8) .order(ByteOrder.nativeOrder()) .asDoubleBuffer(); // create edge coords for (Iterator<EdgeLine> it = internalEdges.keySet().iterator(); it.hasNext(); ) { EdgeLine el = it.next(); nioInternalEdges.put(el.getCoords(grid)); } LineArray la = new NioLineArray(nInternalEdges * 2, GeometryArray.COORDINATES | GeometryArray.COLOR_3); la.setCoordRefBuffer(new J3DBuffer(nioInternalEdges)); int colSize = nInternalEdges * 2 * 3; FloatBuffer nioInternalColors = ByteBuffer.allocateDirect(colSize * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); float[] colors = getColorForOrder(g, 2); for (int i = 0; i < colSize; i += 3) nioInternalColors.put(colors); la.setColorRefBuffer(new J3DBuffer(nioInternalColors)); la.setUserData(new int[] {g, 2}); a = new Appearance(); // pa = new PolygonAttributes(PolygonAttributes.POLYGON_LINE, // PolygonAttributes.CULL_NONE, 0); // pa.setPolygonOffset(4); // pa.setPolygonOffsetFactor(4); // a.setPolygonAttributes(pa); // LineAttributes lat = new LineAttributes(); // lat.setLineAntialiasingEnable(true); // a.setLineAttributes(lat); // RenderingAttributes ra = new RenderingAttributes(); // ra.setAlphaTestFunction(RenderingAttributes.GREATER); // ra.setAlphaTestValue(0.5f); // a.setRenderingAttributes(ra); s3d = new Shape3D(la, a); PickTool.setCapabilities(s3d, PickTool.INTERSECT_FULL); s3d.setCapability(Shape3D.ALLOW_APPEARANCE_READ); s3d.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); s3d.setCapability(Node.ALLOW_PICKABLE_READ); s3d.setCapability(Node.ALLOW_PICKABLE_WRITE); s3d.setPickable(false); // by default, see actions s3d.setUserData(this); // this object will handle edges this.addChild(s3d); allEdgeShapes.add(s3d); } // Now, create external edge int nExternalEdges = 0; for (Iterator<EdgeLine> it = externalEdges.keySet().iterator(); it.hasNext(); ) { EdgeLine el = it.next(); nExternalEdges += el.getNumberOfEdges(); } if (nExternalEdges > 0) { DoubleBuffer nioExternalEdges = ByteBuffer.allocateDirect(nExternalEdges * 2 * 3 * 8) .order(ByteOrder.nativeOrder()) .asDoubleBuffer(); // create edge coords for (Iterator<EdgeLine> it = externalEdges.keySet().iterator(); it.hasNext(); ) { EdgeLine el = it.next(); nioExternalEdges.put(el.getCoords(grid)); } LineArray la = new NioLineArray(nExternalEdges * 2, GeometryArray.COORDINATES | GeometryArray.COLOR_3); la.setCoordRefBuffer(new J3DBuffer(nioExternalEdges)); int colSize = nExternalEdges * 2 * 3; FloatBuffer nioExternalColors = ByteBuffer.allocateDirect(colSize * 4).order(ByteOrder.nativeOrder()).asFloatBuffer(); float[] colors = getColorForOrder(g, 4); for (int i = 0; i < colSize; i += 3) nioExternalColors.put(colors); la.setColorRefBuffer(new J3DBuffer(nioExternalColors)); la.setUserData(new int[] {g, 4}); a = new Appearance(); // pa = new PolygonAttributes(PolygonAttributes.POLYGON_LINE, // PolygonAttributes.CULL_NONE, 0); // pa.setPolygonOffset(3); // pa.setPolygonOffsetFactor(3); // a.setPolygonAttributes(pa); s3d = new Shape3D(la, a); PickTool.setCapabilities(s3d, PickTool.INTERSECT_FULL); s3d.setCapability(Shape3D.ALLOW_APPEARANCE_READ); s3d.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); s3d.setCapability(Node.ALLOW_PICKABLE_READ); s3d.setCapability(Node.ALLOW_PICKABLE_WRITE); s3d.setPickable(false); // by default, see actions s3d.setUserData(this); // this object will handle edges this.addChild(s3d); allEdgeShapes.add(s3d); } totalQuads += plates.length; totalInternalEdges += nInternalEdges; totalExternalEdges += nExternalEdges; } System.out.println("Total quads: " + totalQuads); System.out.println("Total Internal Plate edges: " + totalInternalEdges); System.out.println("Total External Plate edges: " + totalExternalEdges); }