1 /**********************************************************************
2 *
3 * rttopo - topology library
4 * http://git.osgeo.org/gitea/rttopo/librttopo
5 *
6 * rttopo 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 * rttopo 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 rttopo. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright (C) 2010 - Oslandia
22 *
23 **********************************************************************/
24
25
26
27 /* basic RTTRIANGLE manipulation */
28
29 #include "rttopo_config.h"
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #include "librttopo_geom_internal.h"
34 #include "rtgeom_log.h"
35
36
37
38 /* construct a new RTTRIANGLE.
39 * use SRID=SRID_UNKNOWN for unknown SRID (will have 8bit type's S = 0)
40 */
41 RTTRIANGLE*
rttriangle_construct(const RTCTX * ctx,int srid,RTGBOX * bbox,RTPOINTARRAY * points)42 rttriangle_construct(const RTCTX *ctx, int srid, RTGBOX *bbox, RTPOINTARRAY *points)
43 {
44 RTTRIANGLE *result;
45
46 result = (RTTRIANGLE*) rtalloc(ctx, sizeof(RTTRIANGLE));
47 result->type = RTTRIANGLETYPE;
48
49 result->flags = points->flags;
50 RTFLAGS_SET_BBOX(result->flags, bbox?1:0);
51
52 result->srid = srid;
53 result->points = points;
54 result->bbox = bbox;
55
56 return result;
57 }
58
59 RTTRIANGLE*
rttriangle_construct_empty(const RTCTX * ctx,int srid,char hasz,char hasm)60 rttriangle_construct_empty(const RTCTX *ctx, int srid, char hasz, char hasm)
61 {
62 RTTRIANGLE *result = rtalloc(ctx, sizeof(RTTRIANGLE));
63 result->type = RTTRIANGLETYPE;
64 result->flags = gflags(ctx, hasz,hasm,0);
65 result->srid = srid;
66 result->points = ptarray_construct_empty(ctx, hasz, hasm, 1);
67 result->bbox = NULL;
68 return result;
69 }
70
rttriangle_free(const RTCTX * ctx,RTTRIANGLE * triangle)71 void rttriangle_free(const RTCTX *ctx, RTTRIANGLE *triangle)
72 {
73 if ( ! triangle ) return;
74
75 if (triangle->bbox)
76 rtfree(ctx, triangle->bbox);
77
78 if (triangle->points)
79 ptarray_free(ctx, triangle->points);
80
81 rtfree(ctx, triangle);
82 }
83
printRTTRIANGLE(const RTCTX * ctx,RTTRIANGLE * triangle)84 void printRTTRIANGLE(const RTCTX *ctx, RTTRIANGLE *triangle)
85 {
86 if (triangle->type != RTTRIANGLETYPE)
87 rterror(ctx, "printRTTRIANGLE called with something else than a Triangle");
88
89 rtnotice(ctx, "RTTRIANGLE {");
90 rtnotice(ctx, " ndims = %i", (int)RTFLAGS_NDIMS(triangle->flags));
91 rtnotice(ctx, " SRID = %i", (int)triangle->srid);
92 printPA(ctx, triangle->points);
93 rtnotice(ctx, "}");
94 }
95
96 /* @brief Clone RTTRIANGLE object. Serialized point lists are not copied.
97 *
98 * @see ptarray_clone
99 */
100 RTTRIANGLE *
rttriangle_clone(const RTCTX * ctx,const RTTRIANGLE * g)101 rttriangle_clone(const RTCTX *ctx, const RTTRIANGLE *g)
102 {
103 RTDEBUGF(ctx, 2, "rttriangle_clone called with %p", g);
104 return (RTTRIANGLE *)rtline_clone(ctx, (const RTLINE *)g);
105 }
106
107 void
rttriangle_force_clockwise(const RTCTX * ctx,RTTRIANGLE * triangle)108 rttriangle_force_clockwise(const RTCTX *ctx, RTTRIANGLE *triangle)
109 {
110 if ( ptarray_isccw(ctx, triangle->points) )
111 ptarray_reverse(ctx, triangle->points);
112 }
113
114 void
rttriangle_reverse(const RTCTX * ctx,RTTRIANGLE * triangle)115 rttriangle_reverse(const RTCTX *ctx, RTTRIANGLE *triangle)
116 {
117 if( rttriangle_is_empty(ctx, triangle) ) return;
118 ptarray_reverse(ctx, triangle->points);
119 }
120
121 void
rttriangle_release(const RTCTX * ctx,RTTRIANGLE * rttriangle)122 rttriangle_release(const RTCTX *ctx, RTTRIANGLE *rttriangle)
123 {
124 rtgeom_release(ctx, rttriangle_as_rtgeom(ctx, rttriangle));
125 }
126
127 /* check coordinate equality */
128 char
rttriangle_same(const RTCTX * ctx,const RTTRIANGLE * t1,const RTTRIANGLE * t2)129 rttriangle_same(const RTCTX *ctx, const RTTRIANGLE *t1, const RTTRIANGLE *t2)
130 {
131 char r = ptarray_same(ctx, t1->points, t2->points);
132 RTDEBUGF(ctx, 5, "returning %d", r);
133 return r;
134 }
135
136 /*
137 * Construct a triangle from a RTLINE being
138 * the shell
139 * Pointarray from intput geom are cloned.
140 * Input line must have 4 points, and be closed.
141 */
142 RTTRIANGLE *
rttriangle_from_rtline(const RTCTX * ctx,const RTLINE * shell)143 rttriangle_from_rtline(const RTCTX *ctx, const RTLINE *shell)
144 {
145 RTTRIANGLE *ret;
146 RTPOINTARRAY *pa;
147
148 if ( shell->points->npoints != 4 )
149 rterror(ctx, "rttriangle_from_rtline: shell must have exactly 4 points");
150
151 if ( (!RTFLAGS_GET_Z(shell->flags) && !ptarray_is_closed_2d(ctx, shell->points)) ||
152 (RTFLAGS_GET_Z(shell->flags) && !ptarray_is_closed_3d(ctx, shell->points)) )
153 rterror(ctx, "rttriangle_from_rtline: shell must be closed");
154
155 pa = ptarray_clone_deep(ctx, shell->points);
156 ret = rttriangle_construct(ctx, shell->srid, NULL, pa);
157
158 if (rttriangle_is_repeated_points(ctx, ret))
159 rterror(ctx, "rttriangle_from_rtline: some points are repeated in triangle");
160
161 return ret;
162 }
163
164 char
rttriangle_is_repeated_points(const RTCTX * ctx,RTTRIANGLE * triangle)165 rttriangle_is_repeated_points(const RTCTX *ctx, RTTRIANGLE *triangle)
166 {
167 char ret;
168 RTPOINTARRAY *pa;
169
170 pa = ptarray_remove_repeated_points(ctx, triangle->points, 0.0);
171 ret = ptarray_same(ctx, pa, triangle->points);
172 ptarray_free(ctx, pa);
173
174 return ret;
175 }
176
rttriangle_is_empty(const RTCTX * ctx,const RTTRIANGLE * triangle)177 int rttriangle_is_empty(const RTCTX *ctx, const RTTRIANGLE *triangle)
178 {
179 if ( !triangle->points || triangle->points->npoints < 1 )
180 return RT_TRUE;
181 return RT_FALSE;
182 }
183
184 /**
185 * Find the area of the outer ring
186 */
187 double
rttriangle_area(const RTCTX * ctx,const RTTRIANGLE * triangle)188 rttriangle_area(const RTCTX *ctx, const RTTRIANGLE *triangle)
189 {
190 double area=0.0;
191 int i;
192 RTPOINT2D p1;
193 RTPOINT2D p2;
194
195 if (! triangle->points->npoints) return area; /* empty triangle */
196
197 for (i=0; i < triangle->points->npoints-1; i++)
198 {
199 rt_getPoint2d_p(ctx, triangle->points, i, &p1);
200 rt_getPoint2d_p(ctx, triangle->points, i+1, &p2);
201 area += ( p1.x * p2.y ) - ( p1.y * p2.x );
202 }
203
204 area /= 2.0;
205
206 return fabs(area);
207 }
208
209
210 double
rttriangle_perimeter(const RTCTX * ctx,const RTTRIANGLE * triangle)211 rttriangle_perimeter(const RTCTX *ctx, const RTTRIANGLE *triangle)
212 {
213 if( triangle->points )
214 return ptarray_length(ctx, triangle->points);
215 else
216 return 0.0;
217 }
218
219 double
rttriangle_perimeter_2d(const RTCTX * ctx,const RTTRIANGLE * triangle)220 rttriangle_perimeter_2d(const RTCTX *ctx, const RTTRIANGLE *triangle)
221 {
222 if( triangle->points )
223 return ptarray_length_2d(ctx, triangle->points);
224 else
225 return 0.0;
226 }
227