private Point3d computeWinCoord( Canvas3D canvas, RenderAtom ra, Point2d winCoord, Point3d objCoord, Transform3D localToImagePlate) { // Get local to Vworld transform RenderMolecule rm = ra.renderMolecule; if (rm == null) { // removeRenderAtom() may set ra.renderMolecule to null // in RenderBin before this renderer thread run. return null; } // MT safe issue: We can't reference ra.renderMolecule below since // RenderBin thread may set it to null anytime. Use rm instead. Transform3D lvw = rm.localToVworld[rm.localToVworldIndex[NodeRetained.LAST_LOCAL_TO_VWORLD]]; Point3d clipCoord3 = new Point3d(); clipCoord3.set(objCoord); Point4d clipCoord4 = new Point4d(); // Transform point from local coord. to clipping coord. lvw.transform(clipCoord3); canvas.vworldToEc.transform(clipCoord3); canvas.projTrans.transform(clipCoord3, clipCoord4); // clip check in Z if ((clipCoord4.w <= 0.0) || (clipCoord4.z > clipCoord4.w) || (-clipCoord4.z > clipCoord4.w)) { return null; } double invW = 1.0 / clipCoord4.w; clipCoord3.x = clipCoord4.x * invW; clipCoord3.y = clipCoord4.y * invW; clipCoord3.z = clipCoord4.z * invW; // Get Vworld to image plate Xform canvas.getLastVworldToImagePlate(localToImagePlate); // v' = vwip x lvw x v // where v' = transformed vertex, // lvw = local to Vworld Xform // vwip = Vworld to Image plate Xform // v = vertex // Compute composite local to image plate Xform localToImagePlate.mul(lvw); // Transform the Raster's position from object to world coordinates localToImagePlate.transform(objCoord); // Get the window coordinates of this point canvas.getPixelLocationFromImagePlate(objCoord, winCoord); return clipCoord3; }
@Override void computeBoundingBox() { if (clipMode == Raster.CLIP_IMAGE) { // Disable view frustum culling by setting the raster's bounds to // infinity. Point3d minBounds = new Point3d(Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.NEGATIVE_INFINITY); Point3d maxBounds = new Point3d(Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY, Double.POSITIVE_INFINITY); geoBounds.setUpper(maxBounds); geoBounds.setLower(minBounds); } else { Point3d center = new Point3d(); center.x = position.x; center.y = position.y; center.z = position.z; geoBounds.setUpper(center); geoBounds.setLower(center); } }
@Override boolean intersect( PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, GeometryRetained geom, int geomIndex) { Point3d pnts[] = new Point3d[2]; double sdist[] = new double[1]; double minDist = Double.MAX_VALUE; double x = 0, y = 0, z = 0; int scount, j, i = 0; int count = 0; int[] vtxIndexArr = new int[2]; pnts[0] = new Point3d(); pnts[1] = new Point3d(); switch (pickShape.getPickType()) { case PickShape.PICKRAY: PickRay pickRay = (PickRay) pickShape; while (i < stripIndexCounts.length) { vtxIndexArr[0] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[0]); scount = stripIndexCounts[i++]; for (j = 1; j < scount; j++) { vtxIndexArr[1] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[1]); if (intersectLineAndRay( pnts[0], pnts[1], pickRay.origin, pickRay.direction, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } pnts[0].set(pnts[1]); vtxIndexArr[0] = vtxIndexArr[1]; } } break; case PickShape.PICKSEGMENT: PickSegment pickSegment = (PickSegment) pickShape; Vector3d dir = new Vector3d( pickSegment.end.x - pickSegment.start.x, pickSegment.end.y - pickSegment.start.y, pickSegment.end.z - pickSegment.start.z); while (i < stripIndexCounts.length) { vtxIndexArr[0] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[0]); scount = stripIndexCounts[i++]; for (j = 1; j < scount; j++) { vtxIndexArr[1] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[1]); if (intersectLineAndRay(pnts[0], pnts[1], pickSegment.start, dir, sdist, iPnt) && (sdist[0] <= 1.0)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } pnts[0].set(pnts[1]); vtxIndexArr[0] = vtxIndexArr[1]; } } break; case PickShape.PICKBOUNDINGBOX: BoundingBox bbox = (BoundingBox) ((PickBounds) pickShape).bounds; while (i < stripIndexCounts.length) { vtxIndexArr[0] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[0]); scount = stripIndexCounts[i++]; for (j = 1; j < scount; j++) { vtxIndexArr[1] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[1]); if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } pnts[0].set(pnts[1]); vtxIndexArr[0] = vtxIndexArr[1]; } } break; case PickShape.PICKBOUNDINGSPHERE: BoundingSphere bsphere = (BoundingSphere) ((PickBounds) pickShape).bounds; while (i < stripIndexCounts.length) { vtxIndexArr[0] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[0]); scount = stripIndexCounts[i++]; for (j = 1; j < scount; j++) { vtxIndexArr[1] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[1]); if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } pnts[0].set(pnts[1]); vtxIndexArr[0] = vtxIndexArr[1]; } } break; case PickShape.PICKBOUNDINGPOLYTOPE: BoundingPolytope bpolytope = (BoundingPolytope) ((PickBounds) pickShape).bounds; while (i < stripIndexCounts.length) { vtxIndexArr[0] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[0]); scount = stripIndexCounts[i++]; for (j = 1; j < scount; j++) { vtxIndexArr[1] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[1]); if (intersectBoundingPolytope(pnts, bpolytope, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } pnts[0].set(pnts[1]); vtxIndexArr[0] = vtxIndexArr[1]; } } break; case PickShape.PICKCYLINDER: PickCylinder pickCylinder = (PickCylinder) pickShape; while (i < stripIndexCounts.length) { vtxIndexArr[0] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[0]); scount = stripIndexCounts[i++]; for (j = 1; j < scount; j++) { vtxIndexArr[1] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[1]); if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } pnts[0].set(pnts[1]); vtxIndexArr[0] = vtxIndexArr[1]; } } break; case PickShape.PICKCONE: PickCone pickCone = (PickCone) pickShape; while (i < stripIndexCounts.length) { vtxIndexArr[0] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[0]); scount = stripIndexCounts[i++]; for (j = 1; j < scount; j++) { vtxIndexArr[1] = indexCoord[count]; getVertexData(indexCoord[count++], pnts[1]); if (intersectCone(pnts, pickCone, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } pnts[0].set(pnts[1]); vtxIndexArr[0] = vtxIndexArr[1]; } } break; case PickShape.PICKPOINT: // Should not happen since API already check for this throw new IllegalArgumentException(J3dI18N.getString("IndexedLineStripArrayRetained0")); default: throw new RuntimeException("PickShape not supported for intersection"); } if (minDist < Double.MAX_VALUE) { iPnt.x = x; iPnt.y = y; iPnt.z = z; return true; } return false; }
@Override synchronized void computeBoundingBox() { Point3d l = new Point3d(); Point3d u = new Point3d(); Vector3f location = new Vector3f(this.position); int i, k = 0, numTotal = 0; double width = 0, height = 0; Rectangle2D bounds; // Reset bounds data l.set(location); u.set(location); if (numChars != 0) { // Set loop counters based on path type if (path == Text3D.PATH_RIGHT || path == Text3D.PATH_UP) { k = 0; numTotal = numChars + 1; } else if (path == Text3D.PATH_LEFT || path == Text3D.PATH_DOWN) { k = 1; numTotal = numChars; // Reset bounds to bounding box if first character bounds = glyphVecs[0].getVisualBounds(); u.x += bounds.getWidth(); u.y += bounds.getHeight(); } for (i = 1; i < numTotal; i++, k++) { width = glyphVecs[k].getLogicalBounds().getWidth(); bounds = glyphVecs[k].getVisualBounds(); // 'switch' could be outside loop with little hacking, width += charSpacing; height = bounds.getHeight(); switch (this.path) { case Text3D.PATH_RIGHT: u.x += (width); if (u.y < (height + location.y)) { u.y = location.y + height; } break; case Text3D.PATH_LEFT: l.x -= (width); if (u.y < (height + location.y)) { u.y = location.y + height; } break; case Text3D.PATH_UP: u.y += height; if (u.x < (bounds.getWidth() + location.x)) { u.x = location.x + bounds.getWidth(); } break; case Text3D.PATH_DOWN: l.y -= height; if (u.x < (bounds.getWidth() + location.x)) { u.x = location.x + bounds.getWidth(); } break; } } // Handle string alignment. ALIGN_FIRST is handled by default if (alignment != Text3D.ALIGN_FIRST) { double cx = (u.x - l.x); double cy = (u.y - l.y); if (alignment == Text3D.ALIGN_CENTER) { cx *= .5; cy *= .5; } switch (path) { case Text3D.PATH_RIGHT: l.x -= cx; u.x -= cx; break; case Text3D.PATH_LEFT: l.x += cx; u.x += cx; break; case Text3D.PATH_UP: l.y -= cy; u.y -= cy; break; case Text3D.PATH_DOWN: l.y += cy; u.y += cy; break; } } } l.z = 0.0f; if ((font3D == null) || (font3D.fontExtrusion == null)) { u.z = l.z; } else { u.z = l.z + font3D.fontExtrusion.length; } }
/** * Update per character transform based on Text3D location, per character size and path. * * <p>WARNING: Caller of this method must make sure SceneGraph is live, else exceptions may be * thrown. */ final void updateTransformData() { int i, k = 0, numTotal = 0; double width = 0, height = 0; Vector3f location = new Vector3f(this.position); Rectangle2D bounds; // Reset bounds data lower.set(location); upper.set(location); charTransforms = new Transform3D[numChars]; for (i = 0; i < numChars; i++) { charTransforms[i] = new Transform3D(); } if (numChars != 0) { charTransforms[0].set(location); // Set loop counters based on path type if (path == Text3D.PATH_RIGHT || path == Text3D.PATH_UP) { k = 0; numTotal = numChars + 1; } else if (path == Text3D.PATH_LEFT || path == Text3D.PATH_DOWN) { k = 1; numTotal = numChars; // Reset bounds to bounding box if first character bounds = glyphVecs[0].getVisualBounds(); upper.x += bounds.getWidth(); upper.y += bounds.getHeight(); } for (i = 1; i < numTotal; i++, k++) { width = glyphVecs[k].getLogicalBounds().getWidth(); bounds = glyphVecs[k].getVisualBounds(); // 'switch' could be outside loop with little hacking, width += charSpacing; height = bounds.getHeight(); switch (this.path) { case Text3D.PATH_RIGHT: location.x += width; upper.x += (width); if (upper.y < (height + location.y)) { upper.y = location.y + height; } break; case Text3D.PATH_LEFT: location.x -= width; lower.x -= (width); if (upper.y < (height + location.y)) { upper.y = location.y + height; } break; case Text3D.PATH_UP: location.y += height; upper.y += height; if (upper.x < (bounds.getWidth() + location.x)) { upper.x = location.x + bounds.getWidth(); } break; case Text3D.PATH_DOWN: location.y -= height; lower.y -= height; if (upper.x < (bounds.getWidth() + location.x)) { upper.x = location.x + bounds.getWidth(); } break; } if (i < numChars) { charTransforms[i].set(location); } } // Handle string alignment. ALIGN_FIRST is handled by default if (alignment != Text3D.ALIGN_FIRST) { double cx = (upper.x - lower.x); double cy = (upper.y - lower.y); if (alignment == Text3D.ALIGN_CENTER) { cx *= .5; cy *= .5; } switch (path) { case Text3D.PATH_RIGHT: for (i = 0; i < numChars; i++) { charTransforms[i].mat[3] -= cx; } lower.x -= cx; upper.x -= cx; break; case Text3D.PATH_LEFT: for (i = 0; i < numChars; i++) { charTransforms[i].mat[3] += cx; } lower.x += cx; upper.x += cx; break; case Text3D.PATH_UP: for (i = 0; i < numChars; i++) { charTransforms[i].mat[7] -= cy; } lower.y -= cy; upper.y -= cy; break; case Text3D.PATH_DOWN: for (i = 0; i < numChars; i++) { charTransforms[i].mat[7] += cy; } lower.y += cy; upper.y += cy; break; } } } lower.z = 0.0f; if ((font3D == null) || (font3D.fontExtrusion == null)) { upper.z = lower.z; } else { upper.z = lower.z + font3D.fontExtrusion.length; } // update geoBounds getBoundingBox(geoBounds); }
@Override boolean intersect( PickShape pickShape, PickInfo pickInfo, int flags, Point3d iPnt, GeometryRetained geom, int geomIndex) { Point3d pnts[] = new Point3d[3]; double sdist[] = new double[1]; double minDist = Double.MAX_VALUE; double x = 0, y = 0, z = 0; int[] vtxIndexArr = new int[3]; // NVaidya // Bug 447: While loops below now traverse over all // elements in the valid index range from initialIndexIndex // to initialIndexInex + validIndexCount - 1 int i = initialIndexIndex; int loopStopIndex = initialIndexIndex + validIndexCount; pnts[0] = new Point3d(); pnts[1] = new Point3d(); pnts[2] = new Point3d(); switch (pickShape.getPickType()) { case PickShape.PICKRAY: PickRay pickRay = (PickRay) pickShape; while (i < loopStopIndex) { for (int j = 0; j < 3; j++) { vtxIndexArr[j] = indexCoord[i]; getVertexData(indexCoord[i++], pnts[j]); } if (intersectRay(pnts, pickRay, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } } break; case PickShape.PICKSEGMENT: PickSegment pickSegment = (PickSegment) pickShape; while (i < loopStopIndex) { for (int j = 0; j < 3; j++) { vtxIndexArr[j] = indexCoord[i]; getVertexData(indexCoord[i++], pnts[j]); } if (intersectSegment(pnts, pickSegment.start, pickSegment.end, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } } break; case PickShape.PICKBOUNDINGBOX: BoundingBox bbox = (BoundingBox) ((PickBounds) pickShape).bounds; while (i < loopStopIndex) { for (int j = 0; j < 3; j++) { vtxIndexArr[j] = indexCoord[i]; getVertexData(indexCoord[i++], pnts[j]); } if (intersectBoundingBox(pnts, bbox, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } } break; case PickShape.PICKBOUNDINGSPHERE: BoundingSphere bsphere = (BoundingSphere) ((PickBounds) pickShape).bounds; while (i < loopStopIndex) { for (int j = 0; j < 3; j++) { vtxIndexArr[j] = indexCoord[i]; getVertexData(indexCoord[i++], pnts[j]); } if (intersectBoundingSphere(pnts, bsphere, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } } break; case PickShape.PICKBOUNDINGPOLYTOPE: BoundingPolytope bpolytope = (BoundingPolytope) ((PickBounds) pickShape).bounds; while (i < loopStopIndex) { for (int j = 0; j < 3; j++) { vtxIndexArr[j] = indexCoord[i]; getVertexData(indexCoord[i++], pnts[j]); } if (intersectBoundingPolytope(pnts, bpolytope, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } } break; case PickShape.PICKCYLINDER: PickCylinder pickCylinder = (PickCylinder) pickShape; while (i < loopStopIndex) { for (int j = 0; j < 3; j++) { vtxIndexArr[j] = indexCoord[i]; getVertexData(indexCoord[i++], pnts[j]); } if (intersectCylinder(pnts, pickCylinder, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } } break; case PickShape.PICKCONE: PickCone pickCone = (PickCone) pickShape; while (i < loopStopIndex) { for (int j = 0; j < 3; j++) { vtxIndexArr[j] = indexCoord[i]; getVertexData(indexCoord[i++], pnts[j]); } if (intersectCone(pnts, pickCone, sdist, iPnt)) { if (flags == 0) { return true; } if (sdist[0] < minDist) { minDist = sdist[0]; x = iPnt.x; y = iPnt.y; z = iPnt.z; if ((flags & PickInfo.CLOSEST_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } if ((flags & PickInfo.ALL_GEOM_INFO) != 0) { storeInterestData(pickInfo, flags, geom, geomIndex, vtxIndexArr, iPnt, sdist[0]); } } } break; case PickShape.PICKPOINT: // Should not happen since API already check for this throw new IllegalArgumentException(J3dI18N.getString("IndexedTriangleArrayRetained0")); default: throw new RuntimeException("PickShape not supported for intersection"); } if (minDist < Double.MAX_VALUE) { iPnt.x = x; iPnt.y = y; iPnt.z = z; return true; } return false; }