1 
2 /* autopano-sift, Automatic panorama image creation
3  * Copyright (C) 2004 -- Sebastian Nowozin
4  *
5  * This program is free software released under the GNU General Public
6  * License, which is included in this software package (doc/LICENSE).
7  */
8 
9 /* AreaFilter.cs
10  *
11  * Area maximizing match filtration using convex hull and polygon-area
12  * maximization.
13  *
14  * (C) Copyright 2004 -- Sebastian Nowozin (nowozin@cs.tu-berlin.de)
15  *
16  * Convex hull code based on Ken Clarksons original C implementation.
17  * Polygon area formula by Paul Bourke.
18  */
19 
20 #include "AutoPanoSift.h"
21 
22 #ifdef TEST_MAIN
main(int argc,char * argv[])23 int main (int argc, char* argv[])
24 {
25 	ArrayList* al = ArrayList_new0 (FilterPoint_delete);
26 	Random* rnd = Random_new0 ();
27 
28 	int n;
29 	for (n = 0 ; n < 10 ; ++n) {
30 		FilterPoint* p = FilterPoint_new0 ();
31 
32 		p->x = Random_NextDouble(rnd) * 400.0;
33 		p->y = Random_NextDouble(rnd) * 400.0;
34 
35 		ArrayList_AddItem(al, p);
36 	}
37 	int i;
38 	for(i=0; i<ArrayList_Count(al); i++) {
39 		FilterPoint* p = ArrayList_GetItem(al, i);
40 		WriteLine ("%f %f # GNUPLOT1", p->x, p->y);
41 	}
42 
43 	AreaFilter* conv = AreaFilter_new0 ();
44 	ArrayList* hull = AreaFilter_CreateConvexHull(conv, al);
45 
46 	WriteLine ("\nhull: %d elements", ArrayList_Count(hull));
47 	int j;
48 	for(j=0; j<ArrayList_Count(hull); j++) {
49 		FilterPoint* p = ArrayList_GetItem(hull, j);
50 		WriteLine ("%f %f # GNUPLOT2", p->x, p->y);
51 	}
52 
53 	WriteLine ("\npolygon area: %f", AreaFilter_PolygonArea(conv, hull));
54 	ArrayList_delete(al);
55 	return 0;
56 }
57 
58 #else
59 
AreaFilter_new0()60 AreaFilter* AreaFilter_new0()
61 {
62 	AreaFilter* self = (AreaFilter*)malloc(sizeof(AreaFilter));
63 	return self;
64 }
65 
AreaFilter_delete(AreaFilter * self)66 void AreaFilter_delete(AreaFilter* self)
67 {
68 	if (self) {
69 		free(self);
70 	}
71 }
72 
73 // Measure the absolute area of a non self-intersecting polygon.
74 // Formula by Paul Bourke
75 // (http://astronomy.swin.edu.au/~pbourke/geometry/polyarea/)
76 //
77 // The input points must be ordered (clock- or counter-clockwise). The
78 // polygon is closed automatically between the first and the last point,
79 // so there should not be two same points in the polygon point set.
AreaFilter_PolygonArea(AreaFilter * self,ArrayList * orderedPoints)80 double AreaFilter_PolygonArea (AreaFilter* self, ArrayList* orderedPoints)
81 {
82 	double A = 0.0;
83 
84 	int n;
85 	for (n = 0 ; n < ArrayList_Count(orderedPoints) ; ++n) {
86 		FilterPoint* p0 = (FilterPoint*) ArrayList_GetItem(orderedPoints,n);
87 		FilterPoint* p1 = (FilterPoint*) ArrayList_GetItem(orderedPoints, (n + 1) % ArrayList_Count(orderedPoints));
88 
89 		A += p0->x * p1->y - p1->x * p0->y;
90 	}
91 
92 	A *= 0.5;
93 
94 	return (abs (A));
95 }
96 
97 // Create the convex hull of a point set.
AreaFilter_CreateConvexHull(AreaFilter * self,ArrayList * points)98 ArrayList* AreaFilter_CreateConvexHull (AreaFilter* self, ArrayList* points)
99 {
100 	int chn = AreaFilter_CreateHull (self, points);
101 
102 	ArrayList* hull = ArrayList_new0 (NULL);
103 	int k;
104 	for (k = 0 ; k < chn ; ++k)
105 		ArrayList_AddItem(hull, ArrayList_GetItem (points, k));
106 
107 	return (hull);
108 }
109 
AreaFilter_CompareLow(const FilterPoint * p1,const FilterPoint * p2)110 int AreaFilter_CompareLow (const FilterPoint* p1, const FilterPoint* p2)
111 {
112 
113 	double v = p1->x - p2->x;
114 	if (v > 0)
115 		return (1);
116 	if (v < 0)
117 		return (-1);
118 
119 	v = p2->y - p1->y;
120 	if (v > 0)
121 		return (1);
122 	if (v < 0)
123 		return (-1);
124 
125 	// Equal point
126 	return (0);
127 }
128 
AreaFilter_CompareHigh(const FilterPoint * p1,const FilterPoint * p2)129 int AreaFilter_CompareHigh (const FilterPoint* p1, const FilterPoint* p2)
130 {
131 	return AreaFilter_CompareLow(p2, p1);
132 }
133 
134 
AreaFilter_ccw(ArrayList * points,int i,int j,int k)135 bool AreaFilter_ccw (ArrayList* points, int i, int j, int k)
136 {
137 	double a = ((FilterPoint*)ArrayList_GetItem(points, i))->x - ((FilterPoint*)ArrayList_GetItem(points, j))->x;
138 	double b = ((FilterPoint*)ArrayList_GetItem(points, i))->y - ((FilterPoint*)ArrayList_GetItem(points, j))->y;
139 	double c = ((FilterPoint*)ArrayList_GetItem(points, k))->x - ((FilterPoint*)ArrayList_GetItem(points, j))->x;
140 	double d = ((FilterPoint*)ArrayList_GetItem(points, k))->y - ((FilterPoint*)ArrayList_GetItem(points, j))->y;
141 
142 	return ((a * d - b * c) <= 0.0);
143 }
144 
AreaFilter_MakeChain(AreaFilter * self,ArrayList * points,int (* comp)(const FilterPoint *,const FilterPoint *))145 int AreaFilter_MakeChain (AreaFilter* self, ArrayList* points, int (*comp)(const FilterPoint*, const FilterPoint*))
146 {
147 	IComparator comparator;
148 	comparator.compareTo = (int ( *)(IComparator *,const void *,const void *)) comp;
149 	ArrayList_Sort(points, &comparator);
150 
151 	int s = 1;
152 	int pCount = ArrayList_Count(points);
153 	int i;
154 	for (i = 2 ; i < pCount ; ++i) {
155 		int j;
156 		for (j = s ; j >= 1 && AreaFilter_ccw (points, i, j, j - 1) ; --j)
157 			;
158 
159 		s = j + 1;
160 
161 		// Swap
162 		FilterPoint* t = (FilterPoint*) ArrayList_GetItem(points, s);
163 		ArrayList_SetItem(points, s, ArrayList_GetItem(points, i));
164 		ArrayList_SetItem(points, i, t);
165 	}
166 
167 	return (s);
168 }
169 
AreaFilter_CreateHull(AreaFilter * self,ArrayList * points)170 int AreaFilter_CreateHull (AreaFilter* self, ArrayList* points)
171 {
172 	int u = AreaFilter_MakeChain (self, points, AreaFilter_CompareLow);
173 
174 	if (ArrayList_Count(points) == 0)
175 		return (0);
176 	/*
177 	  int k;
178 	  for (k = 0 ; k < u ; ++k)
179 	      WriteLine ("point %d: %f %f", k, ((FilterPoint*)ArrayList_GetItem(points, k)[k])->x,
180                                        	       ((FilterPoint*)ArrayList_GetItem(points, k)[k])->y);
181 	*/
182 
183 	ArrayList* pointsHigh = ArrayList_new(ArrayList_Count(points)+1-u, NULL);
184 	//WriteLine ("points.Length = %d, u = %d", ArrayList_Count(points), u);
185 
186 	ArrayList_Copy (points, u, pointsHigh, 0, ArrayList_Count(points) - u);
187 	ArrayList_SetItem(pointsHigh, ArrayList_Count(pointsHigh) - 1,  ArrayList_GetItem(points, 0));
188 
189 	int h = AreaFilter_MakeChain (self, pointsHigh, AreaFilter_CompareHigh);
190 
191 	int p;
192 	for ( p = u ; p < ArrayList_Count(points) ; ++p) {
193 		ArrayList_SetItem(points, p, ArrayList_GetItem(pointsHigh, p-u));
194 	}
195 
196 	/*
197 	  WriteLine ("h = %d, u = %d", h, u);
198 	  int k;
199 	  for (k = 0 ; k < (h + u) ; ++k)
200 	      WriteLine ("point %d: %f %f", k, ((FilterPoint*)ArrayList_GetItem(points, k)[k])->x,
201                                        	       ((FilterPoint*)ArrayList_GetItem(points, k)[k])->y);
202 	*/
203 
204 	return (h + u);
205 }
206 
207 #endif
208 
209