001/** 002 * Copyright (c) 2011, The University of Southampton and the individual contributors. 003 * All rights reserved. 004 * 005 * Redistribution and use in source and binary forms, with or without modification, 006 * are permitted provided that the following conditions are met: 007 * 008 * * Redistributions of source code must retain the above copyright notice, 009 * this list of conditions and the following disclaimer. 010 * 011 * * Redistributions in binary form must reproduce the above copyright notice, 012 * this list of conditions and the following disclaimer in the documentation 013 * and/or other materials provided with the distribution. 014 * 015 * * Neither the name of the University of Southampton nor the names of its 016 * contributors may be used to endorse or promote products derived from this 017 * software without specific prior written permission. 018 * 019 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 020 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 021 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 022 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 023 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 024 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 025 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 026 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 027 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 028 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 029 */ 030package org.openimaj.math.geometry.shape.algorithm; 031 032import java.util.ArrayList; 033import java.util.List; 034 035import org.openimaj.math.geometry.point.Point2d; 036import org.openimaj.math.geometry.shape.Polygon; 037import org.openimaj.math.geometry.shape.Triangle; 038 039/** 040 * Class representing a convexity defect of a polygon, with methods for finding 041 * said defects. A convexity defect is a triangle formed between two points on 042 * the convex hull of a polygon, and the deepest point on the shape polygon 043 * between the points on the hull. 044 * 045 * @author Jonathon Hare (jsh2@ecs.soton.ac.uk) 046 * 047 */ 048public class ConvexityDefect { 049 /** 050 * The starting point on the convex hull 051 */ 052 public Point2d start; 053 054 /** 055 * The ending point on the convex hull 056 */ 057 public Point2d end; 058 059 /** 060 * The deepest point on the shape polygon 061 */ 062 public Point2d deepestPoint; 063 064 /** 065 * The depth of the deepest point 066 */ 067 public float depth; 068 069 private ConvexityDefect() { 070 } 071 072 /** 073 * Get the triangle represented by this defect. 074 * 075 * @return the triangle represented by this defect. 076 */ 077 public Triangle getTriangle() { 078 return new Triangle(start, deepestPoint, end); 079 } 080 081 /** 082 * Find the defects of the given polygon. The convex hull of the polygon is 083 * computed internally. 084 * 085 * @param p 086 * the polygon 087 * @return a list of all the convexity defexts 088 */ 089 public static List<ConvexityDefect> findDefects(Polygon p) { 090 return findDefects(p, p.calculateConvexHull()); 091 } 092 093 /** 094 * Find the defects of the given polygon, based on the given convex hull 095 * 096 * @param p 097 * the polygon 098 * @param hull 099 * the convex hull of the polygon 100 * @return a list of all the convexity defexts 101 */ 102 public static List<ConvexityDefect> findDefects(Polygon p, Polygon hull) { 103 // test orientation of hull w.r.t poly 104 final int index1 = p.points.indexOf(hull.points.get(0)); 105 final int index2 = p.points.indexOf(hull.points.get(1)); 106 final int index3 = p.points.indexOf(hull.points.get(2)); 107 108 int sign = 0; 109 sign += (index2 > index1) ? 1 : 0; 110 sign += (index3 > index2) ? 1 : 0; 111 sign += (index1 > index3) ? 1 : 0; 112 113 final boolean reverseOri = (sign == 2) ? false : true; 114 115 final List<ConvexityDefect> defects = new ArrayList<ConvexityDefect>(); 116 117 for (int i = 0; i < hull.points.size(); i++) { 118 final ConvexityDefect defect = new ConvexityDefect(); 119 defect.start = hull.get(i); 120 121 if (i == hull.points.size() - 1) { 122 defect.end = hull.get(0); 123 } else { 124 defect.end = hull.get(i + 1); 125 } 126 127 final double dx0 = defect.end.getX() - defect.start.getX(); 128 final double dy0 = defect.end.getY() - defect.start.getY(); 129 final double scale = 1f / Math.sqrt(dx0 * dx0 + dy0 * dy0); 130 131 float depth = 0; 132 boolean isDefect = false; 133 int curi = p.points.indexOf(defect.start); 134 while (true) { 135 if (reverseOri) { 136 curi--; 137 if (curi < 0) 138 curi = p.points.size() - 1; 139 } else { 140 curi++; 141 if (curi >= p.points.size()) 142 curi = 0; 143 } 144 145 final Point2d cur = p.points.get(curi); 146 if (cur == defect.end) 147 break; 148 149 final double dx = (double) cur.getX() - (double) defect.start.getX(); 150 final double dy = (double) cur.getY() - (double) defect.start.getY(); 151 152 /* compute depth */ 153 final double dist = Math.abs(-dy0 * dx + dx0 * dy) * scale; 154 155 if (dist > depth) 156 { 157 depth = (float) dist; 158 defect.deepestPoint = cur; 159 defect.depth = depth; 160 isDefect = true; 161 } 162 } 163 164 if (isDefect) { 165 defects.add(defect); 166 } 167 } 168 169 return defects; 170 } 171}