/**
   * sets the min/max regarding a clipping box
   *
   * @param origin center of the clipping box
   * @param vx first edge
   * @param vy second edge
   * @param vz third edge
   */
  private void setMinMax(Coords origin, Coords vx, Coords vy, Coords vz) {

    GeoPlane3D geo = (GeoPlane3D) getGeoElement();

    CoordMatrix m = geo.getCoordSys().getDrawingMatrix();
    origin.projectPlaneInPlaneCoords(m, o);
    minmaxXFinal[0] = o.getX();
    minmaxYFinal[0] = o.getY();
    minmaxXFinal[1] = o.getX();
    minmaxYFinal[1] = o.getY();
    Coords[] v = new Coords[3];
    vx.projectPlaneInPlaneCoords(m, tmpCoords1);
    v[0] = tmpCoords1.sub(o);
    vy.projectPlaneInPlaneCoords(m, tmpCoords1);
    v[1] = tmpCoords1.sub(o);
    vz.projectPlaneInPlaneCoords(m, tmpCoords1);
    v[2] = tmpCoords1.sub(o);
    for (int i = 0; i < 3; i++) {
      double x = v[i].getX();
      if (x < 0) minmaxXFinal[0] += x; // sub from xmin
      else minmaxXFinal[1] += x; // add to xmax
      double y = v[i].getY();
      if (y < 0) minmaxYFinal[0] += y; // sub from ymin
      else minmaxYFinal[1] += y; // add to ymax
    }
  }
  private void setMinMax(Coords origin, double radius) {
    GeoPlane3D geo = (GeoPlane3D) getGeoElement();

    CoordMatrix m = geo.getCoordSys().getDrawingMatrix();
    origin.projectPlaneInPlaneCoords(m, o);

    double a = radius * INV_SQRT_2;

    minmaxXFinal[0] = o.getX() - a;
    minmaxYFinal[0] = o.getY() - a;
    minmaxXFinal[1] = o.getX() + a;
    minmaxYFinal[1] = o.getY() + a;
  }
 @Override
 public void drawGeometryHiding(Renderer renderer) {
   GeoPlane3D plane = (GeoPlane3D) getGeoElement();
   if (plane.isPlateVisible()) { // || plane.isGridVisible())
     drawPlate(renderer);
     /*
      * renderer.setLayer(getGeoElement().getLayer()-1f); //-1f for
      * z-fighting with planes
      * renderer.getGeometryManager().draw(getGeometryIndex());
      * renderer.getGeometryManager().draw(hidingIndex);
      * renderer.setLayer(0);
      */
   }
 }
  @Override
  public boolean hit(Hitting hitting) {

    if (waitForReset) { // prevent NPE
      return false;
    }

    if (getGeoElement().getAlphaValue() < EuclidianController.MIN_VISIBLE_ALPHA_VALUE) {
      return false;
    }

    GeoPlane3D plane = (GeoPlane3D) getGeoElement();

    // project hitting origin on plane
    if (hitting.isSphere()) {
      hitting.origin.projectPlane(plane.getCoordSys().getDrawingMatrix(), tmpCoords1, tmpCoords2);
    } else {
      hitting.origin.projectPlaneThruVIfPossible(
          plane.getCoordSys().getDrawingMatrix(), hitting.direction, tmpCoords1, tmpCoords2);
    }

    if (!hitting.isInsideClipping(tmpCoords1)) {
      return false;
    }

    double x = tmpCoords2.getX();
    if (x < plane.getXmin()) {
      return false;
    }
    if (x > plane.getXmax()) {
      return false;
    }

    double y = tmpCoords2.getY();
    if (y < plane.getYmin()) {
      return false;
    }
    if (y > plane.getYmax()) {
      return false;
    }

    if (hitting.isSphere()) {
      double d = tmpCoords1.distance(hitting.origin);
      double scale = getView3D().getScale();
      if (d * scale <= hitting.getThreshold()) {
        setZPick(-d, -d);
        return true;
      }

    } else {
      double parameterOnHitting = tmpCoords2.getZ(); // TODO use other for
      // non-parallel
      // projection :
      // -hitting.origin.distance(project[0]);
      setZPick(parameterOnHitting, parameterOnHitting);
      return true;
    }

    return false;
  }
  /**
   * update the geometry
   *
   * @return true
   */
  protected boolean updateGeometry() {

    Renderer renderer = getView3D().getRenderer();
    GeoPlane3D geo = (GeoPlane3D) getGeoElement();
    CoordSys coordsys = geo.getCoordSys();

    float xmin1 = (float) geo.getXmin(), xmax1 = (float) geo.getXmax(), xdelta1 = xmax1 - xmin1;
    float ymin1 = (float) geo.getYmin(), ymax1 = (float) geo.getYmax(), ydelta1 = ymax1 - ymin1;

    // plane
    PlotterSurface surface = renderer.getGeometryManager().getSurface();

    surface.start(geo, getReusableSurfaceIndex());

    surface.setU(xmin1, xmax1);
    surface.setNbU(2);
    surface.setV(ymin1, ymax1);
    surface.setNbV(2);

    if (!getView3D().useClippingCube()) {
      float fading;
      fading = xdelta1 * geo.getFading();
      surface.setUFading(fading, fading);
      fading = ydelta1 * geo.getFading();
      surface.setVFading(fading, fading);
    }
    surface.draw();
    setSurfaceIndex(surface.end());

    // grid
    if (isGridVisible()) {

      PlotterBrush brush = renderer.getGeometryManager().getBrush();

      if (hasTrace()) {
        brush.start(-1);
      } else {
        brush.start(gridIndex);
      }
      removeGeometryIndex(gridIndex);
      float thickness =
          brush.setThickness(getGeoElement().getLineThickness(), (float) getView3D().getScale());

      brush.setColor(getGeoElement().getObjectColor());

      double dx = geo.getGridXd();
      geo.getGridYd();
      double dy;
      if (Double.isNaN(dx)) {
        dx = getView3D().getNumbersDistance();
        dy = dx;
      } else {
        dy = geo.getGridYd();
      }

      brush.setAffineTexture((0f - xmin1) / ydelta1, 0.25f);
      int i0 = (int) (ymin1 / dy);
      if (ymin1 > 0) i0++;
      for (int i = i0; i <= ymax1 / dy; i++)
        brush.segment(
            coordsys.getPointForDrawing(xmin1, i * dy), coordsys.getPointForDrawing(xmax1, i * dy));
      // along y axis
      brush.setAffineTexture((0f - ymin1) / xdelta1, 0.25f);
      i0 = (int) (xmin1 / dx);
      if (xmin1 > 0) i0++;
      for (int i = i0; i <= xmax1 / dx; i++)
        brush.segment(
            coordsys.getPointForDrawing(i * dx, ymin1), coordsys.getPointForDrawing(i * dx, ymax1));

      gridIndex = brush.end();

      brush.start(gridOutlineIndex);
      removeGeometryIndex(gridOutlineIndex);

      boolean showClippingCube = getView3D().showClippingCube();

      // draws the rectangle outline
      if (showClippingCube) {
        brush.setAffineTexture((0f - xmin1) / ydelta1, 0.25f);
      } else brush.setPlainTexture();
      brush.segment(
          coordsys.getPointForDrawing(xmin1, ymax1 - thickness),
          coordsys.getPointForDrawing(xmax1, ymax1 - thickness));
      brush.segment(
          coordsys.getPointForDrawing(xmin1, ymin1 + thickness),
          coordsys.getPointForDrawing(xmax1, ymin1 + thickness));

      if (showClippingCube) {
        brush.setAffineTexture((0f - ymin1) / xdelta1, 0.25f);
      }
      brush.segment(
          coordsys.getPointForDrawing(xmin1 + thickness, ymin1),
          coordsys.getPointForDrawing(xmin1 + thickness, ymax1));
      brush.segment(
          coordsys.getPointForDrawing(xmax1 - thickness, ymin1),
          coordsys.getPointForDrawing(xmax1 - thickness, ymax1));

      gridOutlineIndex = brush.end();
    }

    return true;
  }