1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright (C) 2010 - Oslandia
22  *
23  **********************************************************************/
24 
25 
26 /* basic LWTRIANGLE manipulation */
27 
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include "liblwgeom_internal.h"
32 #include "lwgeom_log.h"
33 
34 
35 
36 /* construct a new LWTRIANGLE.
37  * use SRID=SRID_UNKNOWN for unknown SRID (will have 8bit type's S = 0)
38  */
39 LWTRIANGLE *
lwtriangle_construct(int32_t srid,GBOX * bbox,POINTARRAY * points)40 lwtriangle_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
41 {
42 	LWTRIANGLE *result;
43 
44 	result = (LWTRIANGLE*) lwalloc(sizeof(LWTRIANGLE));
45 	result->type = TRIANGLETYPE;
46 
47 	result->flags = points->flags;
48 	FLAGS_SET_BBOX(result->flags, bbox?1:0);
49 
50 	result->srid = srid;
51 	result->points = points;
52 	result->bbox = bbox;
53 
54 	return result;
55 }
56 
57 LWTRIANGLE *
lwtriangle_construct_empty(int32_t srid,char hasz,char hasm)58 lwtriangle_construct_empty(int32_t srid, char hasz, char hasm)
59 {
60 	LWTRIANGLE *result = lwalloc(sizeof(LWTRIANGLE));
61 	result->type = TRIANGLETYPE;
62 	result->flags = lwflags(hasz,hasm,0);
63 	result->srid = srid;
64 	result->points = ptarray_construct_empty(hasz, hasm, 1);
65 	result->bbox = NULL;
66 	return result;
67 }
68 
lwtriangle_free(LWTRIANGLE * triangle)69 void lwtriangle_free(LWTRIANGLE  *triangle)
70 {
71 	if ( ! triangle ) return;
72 
73 	if (triangle->bbox)
74 		lwfree(triangle->bbox);
75 
76 	if (triangle->points)
77 		ptarray_free(triangle->points);
78 
79 	lwfree(triangle);
80 }
81 
printLWTRIANGLE(LWTRIANGLE * triangle)82 void printLWTRIANGLE(LWTRIANGLE *triangle)
83 {
84 	if (triangle->type != TRIANGLETYPE)
85                 lwerror("printLWTRIANGLE called with something else than a Triangle");
86 
87 	lwnotice("LWTRIANGLE {");
88 	lwnotice("    ndims = %i", (int)FLAGS_NDIMS(triangle->flags));
89 	lwnotice("    SRID = %i", (int)triangle->srid);
90 	printPA(triangle->points);
91 	lwnotice("}");
92 }
93 
94 /* @brief Clone LWTRIANGLE object. Serialized point lists are not copied.
95  *
96  * @see ptarray_clone
97  */
98 LWTRIANGLE *
lwtriangle_clone(const LWTRIANGLE * g)99 lwtriangle_clone(const LWTRIANGLE *g)
100 {
101 	LWDEBUGF(2, "lwtriangle_clone called with %p", g);
102 	return (LWTRIANGLE *)lwline_clone((const LWLINE *)g);
103 }
104 
105 void
lwtriangle_force_clockwise(LWTRIANGLE * triangle)106 lwtriangle_force_clockwise(LWTRIANGLE *triangle)
107 {
108 	if ( ptarray_isccw(triangle->points) )
109 		ptarray_reverse_in_place(triangle->points);
110 }
111 
112 int
lwtriangle_is_clockwise(LWTRIANGLE * triangle)113 lwtriangle_is_clockwise(LWTRIANGLE *triangle)
114 {
115 	return !ptarray_isccw(triangle->points);
116 }
117 
118 void
lwtriangle_release(LWTRIANGLE * lwtriangle)119 lwtriangle_release(LWTRIANGLE *lwtriangle)
120 {
121 	lwgeom_release(lwtriangle_as_lwgeom(lwtriangle));
122 }
123 
124 /* check coordinate equality  */
125 char
lwtriangle_same(const LWTRIANGLE * t1,const LWTRIANGLE * t2)126 lwtriangle_same(const LWTRIANGLE *t1, const LWTRIANGLE *t2)
127 {
128 	char r = ptarray_same(t1->points, t2->points);
129 	LWDEBUGF(5, "returning %d", r);
130 	return r;
131 }
132 
133 static char
lwtriangle_is_repeated_points(LWTRIANGLE * triangle)134 lwtriangle_is_repeated_points(LWTRIANGLE *triangle)
135 {
136 	char ret;
137 	POINTARRAY *pa;
138 
139 	pa = ptarray_remove_repeated_points(triangle->points, 0.0);
140 	ret = ptarray_same(pa, triangle->points);
141 	ptarray_free(pa);
142 
143 	return ret;
144 }
145 
146 /*
147  * Construct a triangle from a LWLINE being
148  * the shell
149  * Pointarray from input geom is cloned.
150  * Input line must have 4 points, and be closed.
151  */
152 LWTRIANGLE *
lwtriangle_from_lwline(const LWLINE * shell)153 lwtriangle_from_lwline(const LWLINE *shell)
154 {
155 	LWTRIANGLE *ret;
156 	POINTARRAY *pa;
157 
158 	if ( shell->points->npoints != 4 )
159 		lwerror("lwtriangle_from_lwline: shell must have exactly 4 points");
160 
161 	if (   (!FLAGS_GET_Z(shell->flags) && !ptarray_is_closed_2d(shell->points)) ||
162 	        (FLAGS_GET_Z(shell->flags) && !ptarray_is_closed_3d(shell->points)) )
163 		lwerror("lwtriangle_from_lwline: shell must be closed");
164 
165 	pa = ptarray_clone_deep(shell->points);
166 	ret = lwtriangle_construct(shell->srid, NULL, pa);
167 
168 	if (lwtriangle_is_repeated_points(ret))
169 		lwerror("lwtriangle_from_lwline: some points are repeated in triangle");
170 
171 	return ret;
172 }
173 
174 /**
175  * Find the area of the outer ring
176  */
177 double
lwtriangle_area(const LWTRIANGLE * triangle)178 lwtriangle_area(const LWTRIANGLE *triangle)
179 {
180 	double area=0.0;
181 	uint32_t i;
182 	POINT2D p1;
183 	POINT2D p2;
184 
185 	if (! triangle->points->npoints) return area; /* empty triangle */
186 
187 	for (i=0; i < triangle->points->npoints-1; i++)
188 	{
189 		getPoint2d_p(triangle->points, i, &p1);
190 		getPoint2d_p(triangle->points, i+1, &p2);
191 		area += ( p1.x * p2.y ) - ( p1.y * p2.x );
192 	}
193 
194 	area  /= 2.0;
195 
196 	return fabs(area);
197 }
198 
199 
200 double
lwtriangle_perimeter(const LWTRIANGLE * triangle)201 lwtriangle_perimeter(const LWTRIANGLE *triangle)
202 {
203 	if( triangle->points )
204 		return ptarray_length(triangle->points);
205 	else
206 		return 0.0;
207 }
208 
209 double
lwtriangle_perimeter_2d(const LWTRIANGLE * triangle)210 lwtriangle_perimeter_2d(const LWTRIANGLE *triangle)
211 {
212 	if( triangle->points )
213 		return ptarray_length_2d(triangle->points);
214 	else
215 		return 0.0;
216 }
217