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