private void setOutput() {
    if (points == null) return;

    // if init points have no labels, all the points and segments
    // of the polygon don't get labels either: in this case we only
    // have the polygon itself as output object
    if (!labelPointsAndSegments) {
      output = new GeoElement[1];
      output[0] = poly;
    }
    // otherwise: points and segments are also output objects
    else {
      // size = poly + points + segments
      GeoSegmentND[] segments = poly.getSegments();
      GeoPoint[] points = poly.getPoints();
      int size = 1 + segments.length + points.length;

      output = new GeoElement[size];
      int k = 0;
      output[k] = poly;

      for (int i = 0; i < segments.length; i++) {
        output[++k] = (GeoElement) segments[i];
      }

      for (int i = 0; i < points.length; i++) {
        output[++k] = points[i];
      }
    }
  }
 public final String toString() {
   // Michael Borcherds 2008-03-30
   // simplified to allow better Chinese translation
   if (poly != null)
     return app.getPlain("SegmentABofC", P.getLabel(), Q.getLabel(), poly.getNameDescription());
   else return app.getPlain("SegmentAB", P.getLabel(), Q.getLabel());
 }
  public AlgoPolygonOperation(
      Construction cons,
      String[] labels,
      GeoPolygon inPoly0,
      GeoPolygon inPoly1,
      int operationType) {

    super(cons);

    ev = cons.getApplication().getEuclidianView();
    this.operationType = operationType;
    this.inPoly0 = inPoly0;
    this.inPoly1 = inPoly1;
    points = new GeoPoint[0];
    poly = new GeoPolygon(cons, points);

    labelPointsAndSegments = true;

    setInputOutput();
    compute();

    // labels given by user or loaded from file
    int labelsLength = labels == null ? 0 : labels.length;

    // poly.setLabel(labels[0]);
    labelsNeedIniting = true;

    if (labelPointsAndSegments) {
      poly.initLabels(labels);
    } else if (labelsLength == 1) {
      poly.setLabel(labels[0]);
    } else {
      poly.setLabel(null);
    }

    labelsNeedIniting = false;
  }
  protected void setInputOutput() {

    input = new GeoElement[2];
    input[0] = inPoly0;
    input[1] = inPoly1;

    // set dependencies
    for (int i = 0; i < input.length; i++) {
      input[i].addAlgorithm(this);
    }
    cons.addToAlgorithmList(this);

    // setOutput(); done in compute

    // parent of output
    poly.setParentAlgorithm(this);
    cons.addToAlgorithmList(this);
  }
  private void updateSegmentsAndPointsLabels(int oldPointNumber) {
    if (labelsNeedIniting) return;

    // set labels only when points have labels
    /*
    labelPointsAndSegments = labelPointsAndSegments || A.isLabelSet() || B.isLabelSet();


    boolean pointsSegmentsShowLabel = labelPointsAndSegments &&
    		(A.isEuclidianVisible() && A.isLabelVisible() ||
    		 B.isEuclidianVisible() && B.isLabelVisible());

     */

    boolean pointsSegmentsShowLabel = true;

    // set labels for points only if the original points had labels
    if (labelPointsAndSegments) {
      for (int i = 0; i < points.length; i++) {
        if (!points[i].isLabelSet()) {
          points[i].setLabel(null);
          points[i].setLabelVisible(pointsSegmentsShowLabel);
        }
      }
    }

    // update all segments and set labels for new segments
    GeoSegmentND[] segments = poly.getSegments();
    for (int i = 0; i < segments.length; i++) {
      GeoElement seg = (GeoElement) segments[i];
      if (labelPointsAndSegments) {
        if (!seg.isLabelSet()) {
          seg.setLabel(null);
          seg.setAuxiliaryObject(true);
          seg.setLabelVisible(pointsSegmentsShowLabel);
        } else {
          pointsSegmentsShowLabel = pointsSegmentsShowLabel || seg.isLabelVisible();
        }
      }

      seg.getParentAlgorithm().update();
    }
  }
  public AlgoJoinPointsSegment(Construction cons, GeoPoint P, GeoPoint Q, GeoPolygon poly) {
    super(cons);

    // make sure that this helper algorithm is updated right after its parent polygon
    if (poly != null) {
      setUpdateAfterAlgo(poly.getParentAlgorithm());
    }

    this.poly = poly;
    this.P = P;
    this.Q = Q;

    s = new GeoSegment(cons, P, Q);
    setInputOutput(); // for AlgoElement

    // compute line through P, Q
    compute();
    setIncidence();
  }
  protected final void compute() {

    ArrayList<Double> xcoord = new ArrayList<Double>();
    ArrayList<Double> ycoord = new ArrayList<Double>();
    double[] coords = new double[6];
    double[] oldCoords = new double[6];

    // Convert input polygons to Area objects
    Area a1 = getArea(inPoly0.getPoints());
    Area a2 = getArea(inPoly1.getPoints());

    // test for empty intersection
    Area testArea = getArea(inPoly0.getPoints());
    testArea.intersect(a2);
    if (testArea.isEmpty()) {
      poly.setUndefined();
    }
    // if intersection is non-empty perform operation
    else {
      switch (operationType) {
        case TYPE_INTERSECTION:
          a1.intersect(a2);
          break;
        case TYPE_UNION:
          a1.add(a2);
          break;
        case TYPE_DIFFERENCE:
          a1.subtract(a2);
          break;
      }

      // Iterate through the path of the result
      // and recover the polygon vertices.

      PathIterator it = a1.getPathIterator(null);

      int type = it.currentSegment(coords);
      it.next();
      oldCoords = coords.clone();
      double epsilon = 1E-10;

      while (!it.isDone()) {
        type = it.currentSegment(coords);
        if (type == PathIterator.SEG_CLOSE) {
          break;
        }
        // Sometimes the Path iterator gives two almost identical points and
        // we only want one of them.
        // TODO: Why does this happen???
        if ((double) Math.abs(oldCoords[0] - coords[0]) > epsilon
            || (double) Math.abs(oldCoords[1] - coords[1]) > epsilon) {
          xcoord.add(coords[0]);
          ycoord.add(coords[1]);
        }
        oldCoords = coords.clone();

        it.next();
      }
    }

    // Update the points array to the correct size
    int n = xcoord.size();
    // System.out.println("number of points: " + n);
    int oldPointNumber = points.length;
    if (n != oldPointNumber) {
      updatePointsArray(n);
      poly.setPoints(points);
      setOutput();
    }

    // Set the points to the new polygon vertices
    for (int k = 0; k < n; k++) {
      points[k].setCoords(xcoord.get(k), ycoord.get(k), 1);
      // System.out.println("vertices: " + xcoord.get(k) + " , " + ycoord.get(k));

    }

    // Compute area of poly (this will also set our poly geo to be defined)
    poly.calcArea();

    // update new points and segments
    if (n != oldPointNumber) {
      updateSegmentsAndPointsLabels(oldPointNumber);
    }
  }
  /** Fills the list of default geos */
  protected void createDefaultGeoElements() {
    defaultGeoElements = new HashMap<Integer, GeoElement>();

    // free point
    GeoPoint freePoint = new GeoPoint(cons);
    //		freePoint.setLocalVariableLabel(app.getPlain("Point") + strFree);
    freePoint.setPointSize(EuclidianView.DEFAULT_POINT_SIZE);
    freePoint.setPointStyle(EuclidianView.POINT_STYLE_DOT);
    freePoint.setLocalVariableLabel("Point" + strFree);
    freePoint.setObjColor(colPoint);
    freePoint.setPointSize(pointSize);
    defaultGeoElements.put(DEFAULT_POINT_FREE, freePoint);

    // dependent point
    GeoPoint depPoint = new GeoPoint(cons);
    //		depPoint.setLocalVariableLabel(app.getPlain("Point") + strDependent);
    depPoint.setPointSize(EuclidianView.DEFAULT_POINT_SIZE);
    depPoint.setPointStyle(EuclidianView.POINT_STYLE_DOT);
    depPoint.setLocalVariableLabel("Point" + strDependent);
    depPoint.setObjColor(colDepPoint);
    depPoint.setPointSize(pointSize);
    defaultGeoElements.put(DEFAULT_POINT_DEPENDENT, depPoint);

    // point on path
    GeoPoint pathPoint = new GeoPoint(cons);
    //		pathPoint.setLocalVariableLabel(app.getPlain("PointOn"));
    pathPoint.setPointSize(EuclidianView.DEFAULT_POINT_SIZE);
    pathPoint.setPointStyle(EuclidianView.POINT_STYLE_DOT);
    pathPoint.setLocalVariableLabel("PointOn");
    pathPoint.setObjColor(colPathPoint);
    pathPoint.setPointSize(pointSize);
    defaultGeoElements.put(DEFAULT_POINT_ON_PATH, pathPoint);

    // point in region
    GeoPoint regionPoint = new GeoPoint(cons);
    //		regionPoint.setLocalVariableLabel(app.getPlain("PointOn"));
    regionPoint.setPointSize(EuclidianView.DEFAULT_POINT_SIZE);
    regionPoint.setPointStyle(EuclidianView.POINT_STYLE_DOT);
    regionPoint.setLocalVariableLabel("PointInRegion");
    regionPoint.setObjColor(colRegionPoint);
    defaultGeoElements.put(DEFAULT_POINT_IN_REGION, regionPoint);

    // complex number (handled like a point)
    GeoPoint complexPoint = new GeoPoint(cons);
    complexPoint.setPointSize(EuclidianView.DEFAULT_POINT_SIZE);
    complexPoint.setPointStyle(EuclidianView.POINT_STYLE_DOT);
    complexPoint.setLocalVariableLabel("PointOn");
    complexPoint.setObjColor(colComplexPoint);
    complexPoint.setPointSize(pointSize);
    defaultGeoElements.put(DEFAULT_POINT_COMPLEX, complexPoint);

    // line
    GeoLine line = new GeoLine(cons);
    //		line.setLocalVariableLabel(app.getPlain("Line"));
    line.setLocalVariableLabel("Line");
    line.setObjColor(colLine);
    defaultGeoElements.put(DEFAULT_LINE, line);

    GeoFunctionNVar inequality = new GeoFunctionNVar(cons, null);
    // inequality.setLocalVariableLabel("Inequality");
    inequality.setObjColor(colInequality);
    inequality.setAlphaValue(DEFAULT_INEQUALITY_ALPHA);
    defaultGeoElements.put(DEFAULT_INEQUALITY, inequality);

    GeoFunction inequality1var = new GeoFunction(cons);
    // inequality.setLocalVariableLabel("Inequality");
    inequality1var.setObjColor(colInequality);
    inequality1var.setAlphaValue(DEFAULT_INEQUALITY_ALPHA);
    defaultGeoElements.put(DEFAULT_INEQUALITY_1VAR, inequality1var);

    // vector
    GeoVector vector = new GeoVector(cons);
    vector.setLocalVariableLabel("Vector");
    vector.setObjColor(colLine);
    defaultGeoElements.put(DEFAULT_VECTOR, vector);

    // polygon
    GeoPolygon polygon = new GeoPolygon(cons, null);
    //		polygon.setLocalVariableLabel(app.getPlain("Polygon"));
    polygon.setLocalVariableLabel("Polygon");
    polygon.setObjColor(colPolygon);
    polygon.setAlphaValue(DEFAULT_POLYGON_ALPHA);
    defaultGeoElements.put(DEFAULT_POLYGON, polygon);

    // conic
    GeoConic conic = new GeoConic(cons);
    //		conic.setLocalVariableLabel(app.getPlain("Conic"));
    conic.setLocalVariableLabel("Conic");
    conic.setObjColor(colConic);
    defaultGeoElements.put(DEFAULT_CONIC, conic);

    // conic sector
    GeoConicPart conicSector = new GeoConicPart(cons, GeoConicPart.CONIC_PART_SECTOR);
    //		conicSector.setLocalVariableLabel(app.getPlain("Sector"));
    conicSector.setLocalVariableLabel("Sector");
    conicSector.setObjColor(colPolygon);
    conicSector.setAlphaValue(DEFAULT_POLYGON_ALPHA);
    defaultGeoElements.put(DEFAULT_CONIC_SECTOR, conicSector);

    // number
    GeoNumeric number = new GeoNumeric(cons);
    //		number.setLocalVariableLabel(app.getPlain("Numeric"));
    number.setLocalVariableLabel("Numeric");
    number.setSliderFixed(true);
    number.setLabelMode(GeoElement.LABEL_NAME_VALUE);
    /*we have to set min/max/increment/speed here because
    SetEuclideanVisible takes these from default geo*/
    number.setIntervalMax(GeoNumeric.DEFAULT_SLIDER_MAX);
    number.setIntervalMin(GeoNumeric.DEFAULT_SLIDER_MIN);
    number.setAnimationStep(GeoNumeric.DEFAULT_SLIDER_INCREMENT);
    number.setAnimationSpeed(GeoNumeric.DEFAULT_SLIDER_SPEED);
    defaultGeoElements.put(DEFAULT_NUMBER, number);

    // angle
    GeoAngle angle = new GeoAngle(cons);
    //		angle.setLocalVariableLabel(app.getPlain("Angle"));
    angle.setLocalVariableLabel("Angle");
    angle.setSliderFixed(true);
    angle.setObjColor(colAngle);
    angle.setAlphaValue(DEFAULT_ANGLE_ALPHA);
    angle.setArcSize(angleSize);
    /*we have to set min/max/increment/speed here because
    SetEuclideanVisible takes these from default geo*/
    angle.setIntervalMax(GeoAngle.DEFAULT_SLIDER_MAX);
    angle.setIntervalMin(GeoAngle.DEFAULT_SLIDER_MIN);
    angle.setAnimationStep(GeoAngle.DEFAULT_SLIDER_INCREMENT);
    angle.setAnimationSpeed(GeoAngle.DEFAULT_SLIDER_SPEED);
    defaultGeoElements.put(DEFAULT_ANGLE, angle);

    // function
    GeoFunction function = new GeoFunction(cons);
    //		function.setLocalVariableLabel(app.getPlain("Function"));
    function.setLocalVariableLabel("Function");
    function.setObjColor(colFunction);
    defaultGeoElements.put(DEFAULT_FUNCTION, function);

    // locus
    GeoLocus locus = new GeoLocus(cons);
    //		locus.setLocalVariableLabel(app.getPlain("Locus"));
    locus.setLocalVariableLabel("Locus");
    locus.setObjColor(colLocus);
    locus.setLabelVisible(false);
    defaultGeoElements.put(DEFAULT_LOCUS, locus);

    // text
    GeoText text = new GeoText(cons);
    //		text.setLocalVariableLabel(app.getPlain("Text"));
    text.setLocalVariableLabel("Text");
    defaultGeoElements.put(DEFAULT_TEXT, text);

    // image
    GeoImage img = new GeoImage(cons);
    //		img.setLocalVariableLabel(app.getPlain("Image"));
    img.setLocalVariableLabel("Image");
    defaultGeoElements.put(DEFAULT_IMAGE, img);

    // boolean
    GeoBoolean bool = new GeoBoolean(cons);
    //		bool.setLocalVariableLabel(app.getPlain("Boolean"));
    bool.setLocalVariableLabel("Boolean");
    defaultGeoElements.put(DEFAULT_BOOLEAN, bool);

    // list
    GeoList list = new GeoList(cons);
    //		list.setLocalVariableLabel(app.getPlain("List"));
    list.setShowAllProperties(true); // show all properties in the defaults dialog
    list.setLocalVariableLabel("List");
    list.setObjColor(colList);
    list.setAlphaValue(-1); // wait until we have an element in the list
    // then we will use the alphaValue of the first element in the list
    // see GeoList.setAlphaValue() and getAlphaValue()
    defaultGeoElements.put(DEFAULT_LIST, list);
  }
 public int getConstructionIndex() {
   if (poly != null) return poly.getConstructionIndex();
   else return super.getConstructionIndex();
 }
 public void remove() {
   super.remove();
   if (poly != null) poly.remove();
 }