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;
  }