/* GeoGebra - Dynamic Mathematics for Everyone http://www.geogebra.org This file is part of GeoGebra. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation. */ package org.geogebra.common.kernel.discrete; import java.util.ArrayList; import java.util.List; import org.geogebra.common.kernel.Construction; import org.geogebra.common.kernel.GraphAlgo; import org.geogebra.common.kernel.Kernel; import org.geogebra.common.kernel.MyPoint; import org.geogebra.common.kernel.SegmentType; import org.geogebra.common.kernel.algos.AlgoElement; import org.geogebra.common.kernel.commands.Commands; import org.geogebra.common.kernel.discrete.geom.Point2D; import org.geogebra.common.kernel.discrete.geom.algorithms.ConvexHull; import org.geogebra.common.kernel.discrete.geom.algorithms.logging.LogEvent; import org.geogebra.common.kernel.geos.GeoElement; import org.geogebra.common.kernel.geos.GeoList; import org.geogebra.common.kernel.geos.GeoLocus; import org.geogebra.common.kernel.kernelND.GeoPointND; /** * Mode of a list. Adapted from AlgoMode * * @author Michael Borcherds * */ public class AlgoConvexHull extends AlgoElement implements GraphAlgo { private GeoList inputList; // input private GeoLocus locus; // output private ArrayList<MyPoint> al; private ArrayList<Point2D> vl; /** * @param cons * cons * @param label * label * @param inputList * list of GeoPoints */ public AlgoConvexHull(Construction cons, String label, GeoList inputList) { super(cons); this.inputList = inputList; locus = new GeoLocus(cons); setInputOutput(); compute(); locus.setLabel(label); } @Override public Commands getClassName() { return Commands.ConvexHull; } @Override protected void setInputOutput() { input = new GeoElement[1]; input[0] = inputList; setOnlyOutput(locus); setDependencies(); // done by AlgoElement } /** * @return convex hull as a GeoLocus */ public GeoLocus getResult() { return locus; } @Override public void compute() { int size = inputList.size(); if (!inputList.isDefined() || size == 0) { locus.setUndefined(); return; } if (vl == null) { vl = new ArrayList<Point2D>(); } else { vl.clear(); } double inhom[] = new double[2]; for (int i = 0; i < size; i++) { GeoElement geo = inputList.get(i); if (geo.isDefined() && geo.isGeoPoint()) { GeoPointND p = (GeoPointND) geo; p.getInhomCoords(inhom); // make sure duplicates aren't added if (!contains(vl, inhom[0], inhom[1])) { if (Double.isNaN(inhom[0]) || Double.isNaN(inhom[1])) { locus.setUndefined(); return; } vl.add(new Point2D(inhom[0], inhom[1])); } } } if (al == null) { al = new ArrayList<MyPoint>(); } else { al.clear(); } if (vl.size() == 1) { Point2D p = vl.get(0); al.add(new MyPoint(p.getX(), p.getY(), SegmentType.MOVE_TO)); al.add(new MyPoint(p.getX(), p.getY(), SegmentType.LINE_TO)); locus.setPoints(al); locus.setDefined(true); return; } if (vl.size() == 0) { locus.setUndefined(); return; } List<Point2D> jarvisResult = ConvexHull.jarvisMarch(vl, new ArrayList<LogEvent>()); for (int i = 0; i < jarvisResult.size(); i++) { Point2D p = jarvisResult.get(i); al.add(new MyPoint(p.getX(), p.getY(), i != 0 ? SegmentType.LINE_TO : SegmentType.MOVE_TO)); } if (jarvisResult.size() == 0) { locus.setDefined(false); return; } // close the polygon Point2D p = jarvisResult.get(0); al.add(new MyPoint(p.getX(), p.getY(), SegmentType.LINE_TO)); locus.setPoints(al); locus.setDefined(true); } private static boolean contains(ArrayList<Point2D> vl2, double x, double y) { for (int i = 0; i < vl2.size(); i++) { Point2D p = vl2.get(i); if (Kernel.isEqual(p.getX(), x) && Kernel.isEqual(p.getY(), y)) { return true; } } return false; } }