1 /* GTS - Library for the manipulation of triangulated surfaces
2 * Copyright (C) 1999 Stéphane Popinet
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
23 static void cluster_destroy (GtsObject
* object
)
25 GtsCluster
* c
= GTS_CLUSTER (object
);
27 if (c
->v
&& gts_vertex_is_unattached (c
->v
))
28 gts_object_destroy (GTS_OBJECT (c
->v
));
30 /* do not forget to call destroy method of the parent */
31 (* GTS_OBJECT_CLASS (gts_cluster_class ())->parent_class
->destroy
) (object
);
34 static void cluster_add (GtsCluster
* c
, GtsPoint
* p
, gpointer data
)
38 g_return_if_fail (c
!= NULL
);
39 g_return_if_fail (c
->v
!= NULL
);
40 g_return_if_fail (p
!= NULL
);
42 cp
= GTS_POINT (c
->v
);
50 static void cluster_update (GtsCluster
* c
)
54 g_return_if_fail (c
!= NULL
);
55 g_return_if_fail (c
->v
!= NULL
);
65 static void cluster_class_init (GtsClusterClass
* klass
)
67 klass
->add
= cluster_add
;
68 klass
->update
= cluster_update
;
70 GTS_OBJECT_CLASS (klass
)->destroy
= cluster_destroy
;
73 static void cluster_init (GtsCluster
* c
)
82 * Returns: the #GtsClusterClass.
84 GtsClusterClass
* gts_cluster_class (void)
86 static GtsClusterClass
* klass
= NULL
;
89 GtsObjectClassInfo cluster_info
= {
92 sizeof (GtsClusterClass
),
93 (GtsObjectClassInitFunc
) cluster_class_init
,
94 (GtsObjectInitFunc
) cluster_init
,
98 klass
= gts_object_class_new (gts_object_class (), &cluster_info
);
106 * @klass: a #GtsClusterClass.
107 * @id: the id of the new cluster.
108 * @vklass: a #GtsVertexClass for the representative vertex of the cluster.
110 * Returns: a new #GtsCluster.
112 GtsCluster
* gts_cluster_new (GtsClusterClass
* klass
,
114 GtsVertexClass
* vklass
)
118 c
= GTS_CLUSTER (gts_object_new (GTS_OBJECT_CLASS (klass
)));
120 c
->v
= gts_vertex_new (vklass
, 0., 0., 0.);
129 * @data: data to pass to the add() virtual method of #GtsClusterClass.
131 * Adds point @p to cluster @c.
133 void gts_cluster_add (GtsCluster
* c
, GtsPoint
* p
, gpointer data
)
135 g_return_if_fail (c
!= NULL
);
136 g_return_if_fail (p
!= NULL
);
138 (* GTS_CLUSTER_CLASS (GTS_OBJECT (c
)->klass
)->add
) (c
, p
, data
);
142 * gts_cluster_update:
145 * Updates the position of the vertex representative of all the
146 * vertices added to @c.
148 void gts_cluster_update (GtsCluster
* c
)
150 g_return_if_fail (c
!= NULL
);
152 (* GTS_CLUSTER_CLASS (GTS_OBJECT (c
)->klass
)->update
) (c
);
155 static void destroy_cluster (GtsClusterId
* id
, GtsObject
* cluster
)
157 gts_object_destroy (cluster
);
160 static void cluster_grid_destroy (GtsObject
* object
)
162 GtsClusterGrid
* cluster_grid
= GTS_CLUSTER_GRID (object
);
164 g_hash_table_foreach (cluster_grid
->clusters
,
165 (GHFunc
) destroy_cluster
, NULL
);
166 g_hash_table_destroy (cluster_grid
->clusters
);
168 (* GTS_OBJECT_CLASS (gts_cluster_grid_class ())->parent_class
->destroy
)
172 static void cluster_grid_class_init (GtsClusterGridClass
* klass
)
174 GTS_OBJECT_CLASS (klass
)->destroy
= cluster_grid_destroy
;
177 static gint
cluster_id_equal (gconstpointer v1
,
180 const GtsClusterId
* id1
= (const GtsClusterId
*) v1
;
181 const GtsClusterId
* id2
= (const GtsClusterId
*) v2
;
182 return ((id1
->x
== id2
->x
) && (id1
->y
== id2
->y
) && (id1
->z
== id2
->z
));
185 static guint
cluster_id_hash (gconstpointer key
)
187 const GtsClusterId
* id
= (const GtsClusterId
*) key
;
188 return id
->x
+ id
->y
+ id
->z
;
191 static void cluster_grid_init (GtsClusterGrid
* cluster_grid
)
193 cluster_grid
->surface
= NULL
;
194 cluster_grid
->bbox
= NULL
;
195 cluster_grid
->cluster_class
= gts_cluster_class ();
196 cluster_grid
->clusters
= g_hash_table_new (cluster_id_hash
,
201 * gts_cluster_grid_class:
203 * Returns: the #GtsClusterGridClass.
205 GtsClusterGridClass
* gts_cluster_grid_class (void)
207 static GtsClusterGridClass
* klass
= NULL
;
210 GtsObjectClassInfo cluster_grid_info
= {
212 sizeof (GtsClusterGrid
),
213 sizeof (GtsClusterGridClass
),
214 (GtsObjectClassInitFunc
) cluster_grid_class_init
,
215 (GtsObjectInitFunc
) cluster_grid_init
,
216 (GtsArgSetFunc
) NULL
,
219 klass
= gts_object_class_new (gts_object_class (), &cluster_grid_info
);
226 * gts_cluster_grid_new:
227 * @klass: a #GtsClusterGridClass.
228 * @cluster_class: the klass to be used for the vertex clusters.
229 * @s: the simplified surface.
230 * @bbox: bounding box of the surface to be simplified.
231 * @delta: the size of one grid cell of the simplification grid.
233 * Returns: a new #GtsClusterGrid.
235 GtsClusterGrid
* gts_cluster_grid_new (GtsClusterGridClass
* klass
,
236 GtsClusterClass
* cluster_class
,
241 GtsClusterGrid
* cluster_grid
;
244 g_return_val_if_fail (klass
!= NULL
, NULL
);
245 g_return_val_if_fail (cluster_class
!= NULL
, NULL
);
246 g_return_val_if_fail (s
!= NULL
, NULL
);
247 g_return_val_if_fail (bbox
!= NULL
, NULL
);
248 g_return_val_if_fail (delta
> 0., NULL
);
250 size
[0] = ceil ((bbox
->x2
- bbox
->x1
)/delta
);
251 size
[1] = ceil ((bbox
->y2
- bbox
->y1
)/delta
);
252 size
[2] = ceil ((bbox
->z2
- bbox
->z1
)/delta
);
253 g_return_val_if_fail (size
[0] <= 2.*G_MAXINT
+ 2. &&
254 size
[1] <= 2.*G_MAXINT
+ 2. &&
255 size
[2] <= 2.*G_MAXINT
+ 2., NULL
);
257 GTS_CLUSTER_GRID (gts_object_new (GTS_OBJECT_CLASS (klass
)));
258 cluster_grid
->cluster_class
= cluster_class
;
259 cluster_grid
->surface
= s
;
260 cluster_grid
->bbox
= bbox
;
261 cluster_grid
->size
[0] = size
[0];
262 cluster_grid
->size
[1] = size
[1];
263 cluster_grid
->size
[2] = size
[2];
268 static GtsClusterId
cluster_index (GtsPoint
* p
,
272 GtsClusterId id
= {0, 0, 0};
274 g_return_val_if_fail (p
->x
>= bb
->x1
&& p
->x
<= bb
->x2
, id
);
275 g_return_val_if_fail (p
->y
>= bb
->y1
&& p
->y
<= bb
->y2
, id
);
276 g_return_val_if_fail (p
->z
>= bb
->z1
&& p
->z
<= bb
->z2
, id
);
278 id
.x
= (guint
) (p
->x
== bb
->x2
? n
[0] - 1. : n
[0]*(p
->x
- bb
->x1
)/(bb
->x2
- bb
->x1
));
279 id
.y
= (guint
) (p
->y
== bb
->y2
? n
[1] - 1. : n
[1]*(p
->y
- bb
->y1
)/(bb
->y2
- bb
->y1
));
280 id
.z
= (guint
) (p
->z
== bb
->z2
? n
[2] - 1. : n
[2]*(p
->z
- bb
->z1
)/(bb
->z2
- bb
->z1
));
285 static GtsCluster
* cluster_grid_add_point (GtsClusterGrid
* cluster_grid
,
289 GtsClusterId id
= cluster_index (p
,
292 GtsCluster
* c
= g_hash_table_lookup (cluster_grid
->clusters
, &id
);
295 c
= gts_cluster_new (cluster_grid
->cluster_class
, id
,
296 cluster_grid
->surface
->vertex_class
);
297 g_hash_table_insert (cluster_grid
->clusters
, &c
->id
, c
);
300 gts_cluster_add (c
, p
, data
);
306 * gts_cluster_grid_add_triangle:
307 * @cluster_grid: a #GtsClusterGrid.
311 * @data: user data to pass to the cluster add() method.
313 * Adds the triangle defined by @p1, @p2 and @p3 to the respective clusters
316 void gts_cluster_grid_add_triangle (GtsClusterGrid
* cluster_grid
,
322 GtsCluster
* c1
, * c2
, * c3
;
324 g_return_if_fail (cluster_grid
!= NULL
);
325 g_return_if_fail (p1
!= NULL
);
326 g_return_if_fail (p2
!= NULL
);
327 g_return_if_fail (p3
!= NULL
);
328 g_return_if_fail (cluster_grid
->surface
!= NULL
);
330 c1
= cluster_grid_add_point (cluster_grid
, p1
, data
);
331 c2
= cluster_grid_add_point (cluster_grid
, p2
, data
);
332 c3
= cluster_grid_add_point (cluster_grid
, p3
, data
);
334 if (c1
!= c2
&& c2
!= c3
&& c3
!= c1
) {
335 GtsVertex
* v1
, * v2
, * v3
;
336 GtsEdge
* e1
, * e2
, * e3
;
337 gboolean new_edge
= FALSE
;
339 v1
= c1
->v
; v2
= c2
->v
; v3
= c3
->v
;
341 if ((e1
= GTS_EDGE (gts_vertices_are_connected (v1
, v2
))) == NULL
) {
342 e1
= gts_edge_new (cluster_grid
->surface
->edge_class
, v1
, v2
);
345 if ((e2
= GTS_EDGE (gts_vertices_are_connected (v2
, v3
))) == NULL
) {
346 e2
= gts_edge_new (cluster_grid
->surface
->edge_class
, v2
, v3
);
349 if ((e3
= GTS_EDGE (gts_vertices_are_connected (v3
, v1
))) == NULL
) {
350 e3
= gts_edge_new (cluster_grid
->surface
->edge_class
, v3
, v1
);
353 if (new_edge
|| !gts_triangle_use_edges (e1
, e2
, e3
))
354 gts_surface_add_face (cluster_grid
->surface
,
355 gts_face_new (cluster_grid
->surface
->face_class
,
360 static void update_cluster (gint
* id
, GtsCluster
* cluster
, GtsRange
* stats
)
362 gts_cluster_update (cluster
);
363 gts_range_add_value (stats
, cluster
->n
);
367 * gts_cluster_grid_update:
368 * @cluster_grid: a #GtsClusterGrid.
370 * Updates the representative vertices of all the clusters of @cluster_grid.
372 * Returns: a #GtsRange describing the statistics for the number of vertices
373 * added to each cluster of @cluster_grid.
375 GtsRange
gts_cluster_grid_update (GtsClusterGrid
* cluster_grid
)
379 gts_range_init (&stats
);
380 g_return_val_if_fail (cluster_grid
!= NULL
, stats
);
382 g_hash_table_foreach (cluster_grid
->clusters
,
383 (GHFunc
) update_cluster
, &stats
);
384 gts_range_update (&stats
);