001/*******************************************************************************
002 * This software is provided as a supplement to the authors' textbooks on digital
003 *  image processing published by Springer-Verlag in various languages and editions.
004 * Permission to use and distribute this software is granted under the BSD 2-Clause 
005 * "Simplified" License (see http://opensource.org/licenses/BSD-2-Clause). 
006 * Copyright (c) 2006-2016 Wilhelm Burger, Mark J. Burge. All rights reserved. 
007 * Visit http://imagingbook.com for additional details.
008 *******************************************************************************/
009package imagingbook.pub.regions.geometry;
010
011import java.awt.Point;
012import java.awt.geom.Point2D;
013import java.util.ArrayList;
014import java.util.Collection;
015
016import org.apache.commons.math3.geometry.euclidean.twod.Vector2D;
017import org.apache.commons.math3.geometry.euclidean.twod.hull.ConvexHull2D;
018import org.apache.commons.math3.geometry.euclidean.twod.hull.MonotoneChain;
019
020import imagingbook.pub.regions.Contour;
021import imagingbook.pub.regions.RegionLabeling.BinaryRegion;
022
023/**
024 * This class serves to calculate the convex hull of a binary region
025 * or a closed contour, given as a sequence of point coordinates.
026 * It is based on the convex hull implementation provided by the
027 * Apache Commons Math library, in particular the classes 
028 * {@link ConvexHull2D} and {@link MonotoneChain}.
029 * If a region provides an outer contour, then this is used for 
030 * the convex hull computation, otherwise the entire (inner) region
031 * is used.
032 * 
033 * @author W. Burger
034 * @version 2015-12-02
035 */
036public class ConvexHull {
037        
038        private final ConvexHull2D hull;
039        
040        // public constructors ------------------------
041        
042        public ConvexHull(BinaryRegion r) {
043                Contour c = r.getOuterContour();
044                if (c != null) {
045                        hull = makeConvexHull(collectPointList(c));
046                }
047                else {
048                        hull = makeConvexHull(collectPointList(r));
049                }
050        }
051        
052        public ConvexHull(Contour ctr) {
053                hull = makeConvexHull(collectPointList(ctr));
054        }
055        
056        // public methods ------------------------
057        
058        public Point2D[] getVertices() {
059                return toPoint2D(hull.getVertices());
060        }
061        
062        // --------------------------------------------------------------------
063        
064        private Collection<Vector2D> collectPointList(Contour ctr) {
065//              IJ.log("making hull from contour");
066                Collection<Vector2D> points = new ArrayList<Vector2D>();
067                for (Point p : ctr.getPointArray()) {
068                        points.add(new Vector2D(p.x, p.y));
069                }
070                return points;
071        }
072        
073        private Collection<Vector2D> collectPointList(BinaryRegion r) {
074//              IJ.log("making hull from all region points");
075                Collection<Vector2D> points = new ArrayList<Vector2D>();
076                for (Point p : r) {
077                        points.add(new Vector2D(p.x, p.y));
078                }
079                return points;
080        }
081        
082        private ConvexHull2D makeConvexHull(Collection<Vector2D> points) {
083                return new MonotoneChain().generate(points);
084        }
085        
086        private Point2D[] toPoint2D(Vector2D[] vecs) {
087                Point2D[] pnts = new Point2D[vecs.length];
088                for (int i = 0; i < vecs.length; i++) {
089                        pnts[i] = new Point2D.Double(vecs[i].getX(), vecs[i].getY());
090                }
091                return pnts;
092        }
093
094}