/* GTS - Library for the manipulation of triangulated surfaces
* Copyright (C) 1999 Stéphane Popinet
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
#include "gts.h"
static void segment_destroy (GtsObject * object)
{
GtsSegment * segment = GTS_SEGMENT (object);
GtsVertex * v1 = segment->v1;
GtsVertex * v2 = segment->v2;
v1->segments = g_slist_remove (v1->segments, segment);
if (!GTS_OBJECT_DESTROYED (v1) &&
!gts_allow_floating_vertices && v1->segments == NULL)
gts_object_destroy (GTS_OBJECT (v1));
v2->segments = g_slist_remove (v2->segments, segment);
if (!GTS_OBJECT_DESTROYED (v2) &&
!gts_allow_floating_vertices && v2->segments == NULL)
gts_object_destroy (GTS_OBJECT (v2));
(* GTS_OBJECT_CLASS (gts_segment_class ())->parent_class->destroy) (object);
}
static void segment_class_init (GtsObjectClass * klass)
{
klass->destroy = segment_destroy;
}
static void segment_init (GtsSegment * segment)
{
segment->v1 = segment->v2 = NULL;
}
/**
* gts_segment_class:
*
* Returns: the #GtsSegmentClass.
*/
GtsSegmentClass * gts_segment_class (void)
{
static GtsSegmentClass * klass = NULL;
if (klass == NULL) {
GtsObjectClassInfo segment_info = {
"GtsSegment",
sizeof (GtsSegment),
sizeof (GtsSegmentClass),
(GtsObjectClassInitFunc) segment_class_init,
(GtsObjectInitFunc) segment_init,
(GtsArgSetFunc) NULL,
(GtsArgGetFunc) NULL
};
klass = gts_object_class_new (gts_object_class (),
&segment_info);
}
return klass;
}
/**
* gts_segment_new:
* @klass: a #GtsSegmentClass.
* @v1: a #GtsVertex.
* @v2: another #GtsVertex different from @v1.
*
* Returns: a new #GtsSegment linking @v1 and @v2.
*/
GtsSegment * gts_segment_new (GtsSegmentClass * klass,
GtsVertex * v1, GtsVertex * v2)
{
GtsSegment * s;
g_return_val_if_fail (v1 != NULL, NULL);
g_return_val_if_fail (v2 != NULL, NULL);
g_return_val_if_fail (v1 != v2, NULL);
s = GTS_SEGMENT (gts_object_new (GTS_OBJECT_CLASS (klass)));
s->v1 = v1;
s->v2 = v2;
v1->segments = g_slist_prepend (v1->segments, s);
v2->segments = g_slist_prepend (v2->segments, s);
return s;
}
/**
* gts_segment_is_duplicate:
* @s: a #GtsSegment.
*
* Returns: the first #GtsSegment different from @s which shares the
* same endpoints or %NULL if there is none.
*/
GtsSegment * gts_segment_is_duplicate (GtsSegment * s)
{
GSList * i;
GtsVertex * v2;
g_return_val_if_fail (s != NULL, NULL);
v2 = s->v2;
i = s->v1->segments;
if (s->v1 == v2) /* s is degenerate: special treatment */
while (i) {
GtsSegment * s1 = i->data;
if (s1 != s && s1->v1 == v2 && s1->v2 == v2)
return s1;
i = i->next;
}
else /* s is not degenerate */
while (i) {
GtsSegment * s1 = i->data;
if (s1 != s && (s1->v1 == v2 || s1->v2 == v2))
return s1;
i = i->next;
}
return NULL;
}
/**
* gts_segments_are_intersecting:
* @s1: a #GtsSegment.
* @s2: a #GtsSegment.
*
* Returns: %GTS_IN if @s1 and @s2 are intersecting, %GTS_ON if one of the
* endpoints of @s1 (resp. @s2) lies on @s2 (resp. @s1), %GTS_OUT otherwise.
*/
GtsIntersect gts_segments_are_intersecting (GtsSegment * s1, GtsSegment * s2)
{
GtsPoint * p1, * p2, * p3, * p4;
gdouble d1, d2, d3, d4;
g_return_val_if_fail (s1 != NULL && s2 != NULL, FALSE);
p1 = GTS_POINT (s1->v1); p2 = GTS_POINT (s1->v2);
p3 = GTS_POINT (s2->v1); p4 = GTS_POINT (s2->v2);
d1 = gts_point_orientation (p1, p2, p3);
d2 = gts_point_orientation (p1, p2, p4);
if ((d1 > 0.0 && d2 > 0.0) ||
(d1 < 0.0 && d2 < 0.0))
return GTS_OUT;
d3 = gts_point_orientation (p3, p4, p1);
d4 = gts_point_orientation (p3, p4, p2);
if ((d3 > 0.0 && d4 > 0.0) ||
(d3 < 0.0 && d4 < 0.0))
return GTS_OUT;
if (d1 == 0.0 || d2 == 0.0 || d3 == 0.0 || d4 == 0.0)
return GTS_ON;
return GTS_IN;
}
/**
* gts_segment_midvertex:
* @s: a #GtsSegment.
* @klass: a #GtsVertexClass to be used for the new vertex.
*
* Returns: a new #GtsVertex, midvertex of @s.
*/
GtsVertex * gts_segment_midvertex (GtsSegment * s, GtsVertexClass * klass)
{
GtsPoint * p1, * p2;
g_return_val_if_fail (s != NULL, NULL);
g_return_val_if_fail (klass != NULL, NULL);
p1 = GTS_POINT (s->v1); p2 = GTS_POINT (s->v2);
return gts_vertex_new (klass,
(p1->x + p2->x)/2.,
(p1->y + p2->y)/2.,
(p1->z + p2->z)/2.);
}
/**
* gts_segments_from_vertices:
* @vertices: a list of #GtsVertex.
*
* Returns: a list of unique #GtsSegment which have one of their vertices in
* @vertices.
*/
GSList * gts_segments_from_vertices (GSList * vertices)
{
GHashTable * hash;
GSList * segments = NULL, * i;
hash = g_hash_table_new (NULL, NULL);
i = vertices;
while (i) {
GSList * j = GTS_VERTEX (i->data)->segments;
while (j) {
GtsSegment * s = j->data;
if (g_hash_table_lookup (hash, s) == NULL) {
segments = g_slist_prepend (segments, s);
g_hash_table_insert (hash, s, i);
}
j = j->next;
}
i = i->next;
}
g_hash_table_destroy (hash);
return segments;
}
/**
* gts_segment_is_ok:
* @s: a #GtsSegment.
*
* Returns: %TRUE if @s is not degenerate (i.e. @s->v1 != @s->v2) and not
* duplicate, %FALSE otherwise.
*/
gboolean gts_segment_is_ok (GtsSegment * s)
{
g_return_val_if_fail (s != NULL, FALSE);
g_return_val_if_fail (s->v1 != s->v2, FALSE);
g_return_val_if_fail (!gts_segment_is_duplicate (s), FALSE);
g_return_val_if_fail (GTS_OBJECT (s)->reserved == NULL, FALSE);
return TRUE;
}
syntax highlighted by Code2HTML, v. 0.9.1