valentina/src/libs/vobj/delaunay.cpp

1096 lines
25 KiB
C++
Raw Normal View History

/*
** delaunay.c : compute 2D delaunay triangulation in the plane.
** Copyright (C) 2005 Wael El Oraiby <wael.eloraiby@gmail.com>
**
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program 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 General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <QtGlobal>
2022-08-22 10:34:02 +02:00
#if QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
#include "../vmisc/diagnostic.h"
2022-08-22 10:34:02 +02:00
#endif // QT_VERSION < QT_VERSION_CHECK(5, 5, 0)
#include "delaunay.h"
QT_WARNING_PUSH
QT_WARNING_DISABLE_GCC("-Wold-style-cast")
2022-08-08 14:25:14 +02:00
// cppcheck-suppress unknownMacro
QT_WARNING_DISABLE_CLANG("-Wold-style-cast")
QT_WARNING_DISABLE_GCC("-Wcast-qual")
QT_WARNING_DISABLE_CLANG("-Wcast-qual")
2021-09-25 11:42:28 +02:00
QT_WARNING_DISABLE_GCC("-Walloc-zero")
#if PREDICATE == EXACT_PREDICATE
extern void exactinit();
extern real incircle(real* pa, real* pb, real* pc, real* pd);
#endif
#define ON_RIGHT 1
#define ON_SEG 0
#define ON_LEFT -1
#define OUTSIDE -1
#define ON_CIRCLE 0
#define INSIDE 1
struct delaunay_s;
struct face_s;
struct halfedge_s;
struct point2d_s;
#ifdef USE_DOUBLE
# define REAL_ZERO 0.0
# define REAL_ONE 1.0
# define REAL_TWO 2.0
# define REAL_FOUR 4.0
# define TOLERANCE (1024.0 * 1024.0)
#else
# define REAL_ZERO 0.0f
# define REAL_ONE 1.0f
# define REAL_TWO 2.0f
# define REAL_FOUR 4.0f
# define TOLERANCE (16.0f )
#endif
#define EPSILON (REAL_ONE / TOLERANCE)
typedef struct point2d_s point2d_t;
typedef struct face_s face_t;
typedef struct halfedge_s halfedge_t;
typedef struct delaunay_s delaunay_t;
typedef real mat3_t[3][3];
struct point2d_s
{
2014-12-21 11:56:31 +01:00
real x, y; /* point coordinates */
halfedge_t* he; /* point halfedge */
quint32 idx; /* point index in input buffer */
};
struct face_s
{
/* real radius;
2014-12-21 11:56:31 +01:00
real cx, cy;
point2d_t* p[3];
*/
2014-12-21 11:56:31 +01:00
halfedge_t* he; /* a pointing half edge */
quint32 num_verts; /* number of vertices on this face */
};
struct halfedge_s
{
2014-12-21 11:56:31 +01:00
point2d_t* vertex; /* vertex */
halfedge_t* pair; /* pair */
halfedge_t* next; /* next */
halfedge_t* prev; /* next^-1 */
face_t* face; /* halfedge face */
};
struct delaunay_s
{
2014-12-21 11:56:31 +01:00
halfedge_t* rightmost_he; /* right most halfedge */
halfedge_t* leftmost_he; /* left most halfedge */
point2d_t** points; /* pointer to points */
face_t* faces; /* faces of delaunay */
quint32 num_faces; /* face count */
quint32 start_point; /* start point index */
quint32 end_point; /* end point index */
};
/*
* 3x3 matrix determinant
*/
2014-12-21 11:56:31 +01:00
//static real det3( mat3_t *m )
//{
// real res;
2014-12-21 11:56:31 +01:00
// res = ((*m)[0][0]) * (((*m)[1][1]) * ((*m)[2][2]) - ((*m)[1][2]) * ((*m)[2][1]))
// - ((*m)[0][1]) * (((*m)[1][0]) * ((*m)[2][2]) - ((*m)[1][2]) * ((*m)[2][0]))
// + ((*m)[0][2]) * (((*m)[1][0]) * ((*m)[2][1]) - ((*m)[1][1]) * ((*m)[2][0]));
2014-12-21 11:56:31 +01:00
// return res;
//}
/*
* allocate a point
*/
static point2d_t* point_alloc()
{
2014-12-21 11:56:31 +01:00
point2d_t* p;
2014-12-21 11:56:31 +01:00
p = (point2d_t*)malloc(sizeof(point2d_t));
2017-07-05 18:35:34 +02:00
assert( p != nullptr );
// cppcheck-suppress memsetClassFloat
2014-12-21 11:56:31 +01:00
memset(p, 0, sizeof(point2d_t));
2014-12-21 11:56:31 +01:00
return p;
}
/*
* free a point
*/
static void point_free( point2d_t* p )
{
2017-07-05 18:35:34 +02:00
assert( p != nullptr );
2014-12-21 11:56:31 +01:00
free(p);
}
/*
* allocate a halfedge
*/
static halfedge_t* halfedge_alloc()
{
2014-12-21 11:56:31 +01:00
halfedge_t* d;
2014-12-21 11:56:31 +01:00
d = (halfedge_t*)malloc(sizeof(halfedge_t));
2017-07-05 18:35:34 +02:00
assert( d != nullptr );
2014-12-21 11:56:31 +01:00
memset(d, 0, sizeof(halfedge_t));
2014-12-21 11:56:31 +01:00
return d;
}
/*
* free a halfedge
*/
static void halfedge_free( halfedge_t* d )
{
2017-07-05 18:35:34 +02:00
assert( d != nullptr );
2014-12-21 11:56:31 +01:00
memset(d, 0, sizeof(halfedge_t));
free(d);
}
/*
* free all delaunay halfedges
*/
void del_free_halfedges( delaunay_t *del );
void del_free_halfedges( delaunay_t *del )
{
quint32 i;
2014-12-21 11:56:31 +01:00
halfedge_t *d, *sig;
/* if there is nothing to do */
2017-07-05 18:35:34 +02:00
if( del->points == nullptr )
2014-12-21 11:56:31 +01:00
return;
for( i = 0; i <= (del->end_point - del->start_point); i++ )
{
/* free all the halfedges around the point */
d = del->points[i]->he;
2017-07-05 18:35:34 +02:00
if( d != nullptr )
2014-12-21 11:56:31 +01:00
{
do {
sig = d->next;
halfedge_free( d );
d = sig;
} while( d != del->points[i]->he );
2017-07-05 18:35:34 +02:00
del->points[i]->he = nullptr;
2014-12-21 11:56:31 +01:00
}
}
}
/*
* allocate memory for a face
*/
//static face_t* face_alloc()
//{
// face_t *f = (face_t*)malloc(sizeof(face_t));
2017-07-05 18:35:34 +02:00
// assert( f != nullptr );
// memset(f, 0, sizeof(face_t));
// return f;
//}
/*
* free a face
*/
//static void face_free(face_t *f)
//{
2017-07-05 18:35:34 +02:00
// assert( f != nullptr );
// free(f);
//}
/*
* compare 2 points when sorting
*/
static int cmp_points( const void *_pt0, const void *_pt1 )
{
2014-12-21 11:56:31 +01:00
point2d_t *pt0, *pt1;
pt0 = (point2d_t*)(*((point2d_t**)_pt0));
pt1 = (point2d_t*)(*((point2d_t**)_pt1));
if( pt0->x < pt1->x )
return -1;
else if( pt0->x > pt1->x )
return 1;
else if( pt0->y < pt1->y )
return -1;
else if( pt0->y > pt1->y )
return 1;
assert(0 && "2 or more points share the same exact coordinate");
return 0; /* Should not be given! */
}
/*
* classify a point relative to a segment
*/
static int classify_point_seg( point2d_t *s, point2d_t *e, point2d_t *pt )
{
2014-12-21 11:56:31 +01:00
point2d_t se, spt;
real res;
2014-12-21 11:56:31 +01:00
se.x = e->x - s->x;
se.y = e->y - s->y;
2014-12-21 11:56:31 +01:00
spt.x = pt->x - s->x;
spt.y = pt->y - s->y;
2014-12-21 11:56:31 +01:00
res = (( se.x * spt.y ) - ( se.y * spt.x ));
if( res < REAL_ZERO )
return ON_RIGHT;
else if( res > REAL_ZERO )
return ON_LEFT;
2014-12-21 11:56:31 +01:00
return ON_SEG;
}
/*
* classify a point relative to a halfedge, -1 is left, 0 is on, 1 is right
*/
static int del_classify_point( halfedge_t *d, point2d_t *pt )
{
2014-12-21 11:56:31 +01:00
point2d_t *s, *e;
2014-12-21 11:56:31 +01:00
s = d->vertex;
e = d->pair->vertex;
2014-12-21 11:56:31 +01:00
return classify_point_seg(s, e, pt);
}
/*
* return the absolute value
*/
2014-12-21 11:56:31 +01:00
//static real dabs( real a )
//{
// if( a < REAL_ZERO )
// return (-a);
// return a;
//}
/*
* compute the circle given 3 points
*/
#if PREDICATE == LOOSE_PREDICATE
static void compute_circle( point2d_t *pt0, point2d_t *pt1, point2d_t *pt2, real *cx, real *cy, real *radius )
{
2014-12-21 11:56:31 +01:00
mat3_t ma, mbx, mby, mc;
real x0y0, x1y1, x2y2;
real a, bx, by, c;
/* calculate x0y0, .... */
x0y0 = pt0->x * pt0->x + pt0->y * pt0->y;
x1y1 = pt1->x * pt1->x + pt1->y * pt1->y;
x2y2 = pt2->x * pt2->x + pt2->y * pt2->y;
/* setup A matrix */
ma[0][0] = pt0->x;
ma[0][1] = pt0->y;
ma[1][0] = pt1->x;
ma[1][1] = pt1->y;
ma[2][0] = pt2->x;
ma[2][1] = pt2->y;
ma[0][2] = ma[1][2] = ma[2][2] = REAL_ONE;
/* setup Bx matrix */
mbx[0][0] = x0y0;
mbx[1][0] = x1y1;
mbx[2][0] = x2y2;
mbx[0][1] = pt0->y;
mbx[1][1] = pt1->y;
mbx[2][1] = pt2->y;
mbx[0][2] = mbx[1][2] = mbx[2][2] = REAL_ONE;
/* setup By matrix */
mby[0][0] = x0y0;
mby[1][0] = x1y1;
mby[2][0] = x2y2;
mby[0][1] = pt0->x;
mby[1][1] = pt1->x;
mby[2][1] = pt2->x;
mby[0][2] = mby[1][2] = mby[2][2] = REAL_ONE;
/* setup C matrix */
mc[0][0] = x0y0;
mc[1][0] = x1y1;
mc[2][0] = x2y2;
mc[0][1] = pt0->x;
mc[1][1] = pt1->x;
mc[2][1] = pt2->x;
mc[0][2] = pt0->y;
mc[1][2] = pt1->y;
mc[2][2] = pt2->y;
/* compute a, bx, by and c */
a = det3(&ma);
bx = det3(&mbx);
by = -det3(&mby);
c = -det3(&mc);
*cx = bx / (REAL_TWO * a);
*cy = by / (REAL_TWO * a);
*radius = sqrt(bx * bx + by * by - REAL_FOUR * a * c) / (REAL_TWO * dabs(a));
}
#endif
/*
* test if a point is inside a circle given by 3 points, 1 if inside, 0 if outside
*/
static int in_circle( point2d_t *pt0, point2d_t *pt1, point2d_t *pt2, point2d_t *p )
{
#if PREDICATE == EXACT_PREDICATE
2014-12-21 11:56:31 +01:00
real res = incircle(&(pt0->x), &(pt1->x), &(pt2->x), &(p->x));
if( res > REAL_ZERO )
return INSIDE;
else if( res < REAL_ZERO )
return OUTSIDE;
2014-12-21 11:56:31 +01:00
return ON_CIRCLE;
#endif
#if PREDICATE == LOOSE_PREDICATE
2014-12-21 11:56:31 +01:00
real cx, cy, radius;
compute_circle(pt0, pt1, pt2, &cx, &cy, &radius);
real distance = sqrt((p->x - cx) * (p->x - cx) + (p->y - cy) * (p->y - cy));
if( distance < radius - EPSILON )
return INSIDE;
else if(distance > radius + EPSILON )
return OUTSIDE;
return ON_CIRCLE;
#endif
#if PREDICATE == FAST_PREDICATE
2014-12-21 11:56:31 +01:00
mat3_t ma, mbx, mby, mc;
real x0y0, x1y1, x2y2;
real a, bx, by, c, res;
/* calculate x0y0, .... */
x0y0 = pt0->x * pt0->x + pt0->y * pt0->y;
x1y1 = pt1->x * pt1->x + pt1->y * pt1->y;
x2y2 = pt2->x * pt2->x + pt2->y * pt2->y;
/* setup A matrix */
ma[0][0] = pt0->x;
ma[0][1] = pt0->y;
ma[1][0] = pt1->x;
ma[1][1] = pt1->y;
ma[2][0] = pt2->x;
ma[2][1] = pt2->y;
ma[0][2] = ma[1][2] = ma[2][2] = REAL_ONE;
/* setup Bx matrix */
mbx[0][0] = x0y0;
mbx[1][0] = x1y1;
mbx[2][0] = x2y2;
mbx[0][1] = pt0->y;
mbx[1][1] = pt1->y;
mbx[2][1] = pt2->y;
mbx[0][2] = mbx[1][2] = mbx[2][2] = REAL_ONE;
/* setup By matrix */
mby[0][0] = x0y0;
mby[1][0] = x1y1;
mby[2][0] = x2y2;
mby[0][1] = pt0->x;
mby[1][1] = pt1->x;
mby[2][1] = pt2->x;
mby[0][2] = mby[1][2] = mby[2][2] = REAL_ONE;
/* setup C matrix */
mc[0][0] = x0y0;
mc[1][0] = x1y1;
mc[2][0] = x2y2;
mc[0][1] = pt0->x;
mc[1][1] = pt1->x;
mc[2][1] = pt2->x;
mc[0][2] = pt0->y;
mc[1][2] = pt1->y;
mc[2][2] = pt2->y;
/* compute a, bx, by and c */
a = det3(&ma);
bx = det3(&mbx);
by = -det3(&mby);
c = -det3(&mc);
res = a * (p->x * p->x + p->y * p->y ) - bx * p->x - by * p->y + c;
if( res < REAL_ZERO )
return INSIDE;
else if( res > REAL_ZERO )
return OUTSIDE;
return ON_CIRCLE;
#endif
}
/*
* initialize delaunay segment
*/
static int del_init_seg( delaunay_t *del, int start )
{
2014-12-21 11:56:31 +01:00
halfedge_t *d0, *d1;
point2d_t *pt0, *pt1;
2014-12-21 11:56:31 +01:00
/* init delaunay */
del->start_point = static_cast<quint32>(start);
del->end_point = static_cast<quint32>(start + 1);
2014-12-21 11:56:31 +01:00
/* setup pt0 and pt1 */
pt0 = del->points[start];
pt1 = del->points[start + 1];
2014-12-21 11:56:31 +01:00
/* allocate the halfedges and setup them */
d0 = halfedge_alloc();
d1 = halfedge_alloc();
2014-12-21 11:56:31 +01:00
d0->vertex = pt0;
d1->vertex = pt1;
2014-12-21 11:56:31 +01:00
d0->next = d0->prev = d0;
d1->next = d1->prev = d1;
2014-12-21 11:56:31 +01:00
d0->pair = d1;
d1->pair = d0;
2014-12-21 11:56:31 +01:00
pt0->he = d0;
pt1->he = d1;
2014-12-21 11:56:31 +01:00
del->rightmost_he = d1;
del->leftmost_he = d0;
2014-12-21 11:56:31 +01:00
return 0;
}
/*
* initialize delaunay triangle
*/
static int del_init_tri( delaunay_t *del, int start )
{
2014-12-21 11:56:31 +01:00
halfedge_t *d0, *d1, *d2, *d3, *d4, *d5;
point2d_t *pt0, *pt1, *pt2;
2014-12-21 11:56:31 +01:00
/* initiate delaunay */
del->start_point = static_cast<quint32>(start);
del->end_point = static_cast<quint32>(start + 2);
2014-12-21 11:56:31 +01:00
/* setup the points */
pt0 = del->points[start];
pt1 = del->points[start + 1];
pt2 = del->points[start + 2];
2014-12-21 11:56:31 +01:00
/* allocate the 6 halfedges */
d0 = halfedge_alloc();
d1 = halfedge_alloc();
d2 = halfedge_alloc();
d3 = halfedge_alloc();
d4 = halfedge_alloc();
d5 = halfedge_alloc();
2014-12-21 11:56:31 +01:00
if( classify_point_seg(pt0, pt2, pt1) == ON_LEFT ) /* first case */
{
/* set halfedges points */
d0->vertex = pt0;
d1->vertex = pt2;
d2->vertex = pt1;
2014-12-21 11:56:31 +01:00
d3->vertex = pt2;
d4->vertex = pt1;
d5->vertex = pt0;
2014-12-21 11:56:31 +01:00
/* set points halfedges */
pt0->he = d0;
pt1->he = d2;
pt2->he = d1;
2014-12-21 11:56:31 +01:00
/* next and next -1 setup */
d0->next = d5;
d0->prev = d5;
2014-12-21 11:56:31 +01:00
d1->next = d3;
d1->prev = d3;
2014-12-21 11:56:31 +01:00
d2->next = d4;
d2->prev = d4;
2014-12-21 11:56:31 +01:00
d3->next = d1;
d3->prev = d1;
2014-12-21 11:56:31 +01:00
d4->next = d2;
d4->prev = d2;
2014-12-21 11:56:31 +01:00
d5->next = d0;
d5->prev = d0;
2014-12-21 11:56:31 +01:00
/* set halfedges pair */
d0->pair = d3;
d3->pair = d0;
2014-12-21 11:56:31 +01:00
d1->pair = d4;
d4->pair = d1;
2014-12-21 11:56:31 +01:00
d2->pair = d5;
d5->pair = d2;
2014-12-21 11:56:31 +01:00
del->rightmost_he = d1;
del->leftmost_he = d0;
2014-12-21 11:56:31 +01:00
} else /* 2nd case */
{
/* set halfedges points */
d0->vertex = pt0;
d1->vertex = pt1;
d2->vertex = pt2;
2014-12-21 11:56:31 +01:00
d3->vertex = pt1;
d4->vertex = pt2;
d5->vertex = pt0;
2014-12-21 11:56:31 +01:00
/* set points halfedges */
pt0->he = d0;
pt1->he = d1;
pt2->he = d2;
2014-12-21 11:56:31 +01:00
/* next and next -1 setup */
d0->next = d5;
d0->prev = d5;
2014-12-21 11:56:31 +01:00
d1->next = d3;
d1->prev = d3;
2014-12-21 11:56:31 +01:00
d2->next = d4;
d2->prev = d4;
2014-12-21 11:56:31 +01:00
d3->next = d1;
d3->prev = d1;
2014-12-21 11:56:31 +01:00
d4->next = d2;
d4->prev = d2;
2014-12-21 11:56:31 +01:00
d5->next = d0;
d5->prev = d0;
2014-12-21 11:56:31 +01:00
/* set halfedges pair */
d0->pair = d3;
d3->pair = d0;
2014-12-21 11:56:31 +01:00
d1->pair = d4;
d4->pair = d1;
2014-12-21 11:56:31 +01:00
d2->pair = d5;
d5->pair = d2;
2014-12-21 11:56:31 +01:00
del->rightmost_he = d2;
del->leftmost_he = d0;
}
2014-12-21 11:56:31 +01:00
return 0;
}
/*
* remove an edge given a halfedge
*/
static void del_remove_edge( halfedge_t *d )
{
2014-12-21 11:56:31 +01:00
halfedge_t *next, *prev, *pair, *orig_pair;
2014-12-21 11:56:31 +01:00
orig_pair = d->pair;
2014-12-21 11:56:31 +01:00
next = d->next;
prev = d->prev;
pair = d->pair;
2017-07-05 18:35:34 +02:00
assert(next != nullptr);
assert(prev != nullptr);
2014-12-21 11:56:31 +01:00
next->prev = prev;
prev->next = next;
2014-12-21 11:56:31 +01:00
/* check to see if we have already removed pair */
if( pair )
2017-07-05 18:35:34 +02:00
pair->pair = nullptr;
2014-12-21 11:56:31 +01:00
/* check to see if the vertex points to this halfedge */
if( d->vertex->he == d )
d->vertex->he = next;
2017-07-05 18:35:34 +02:00
d->vertex = nullptr;
d->next = nullptr;
d->prev = nullptr;
d->pair = nullptr;
2014-12-21 11:56:31 +01:00
next = orig_pair->next;
prev = orig_pair->prev;
pair = orig_pair->pair;
2017-07-05 18:35:34 +02:00
assert(next != nullptr);
assert(prev != nullptr);
2014-12-21 11:56:31 +01:00
next->prev = prev;
prev->next = next;
2014-12-21 11:56:31 +01:00
/* check to see if we have already removed pair */
if( pair )
2017-07-05 18:35:34 +02:00
pair->pair = nullptr;
2014-12-21 11:56:31 +01:00
/* check to see if the vertex points to this halfedge */
if( orig_pair->vertex->he == orig_pair )
orig_pair->vertex->he = next;
2017-07-05 18:35:34 +02:00
orig_pair->vertex = nullptr;
orig_pair->next = nullptr;
orig_pair->prev = nullptr;
orig_pair->pair = nullptr;
2014-12-21 11:56:31 +01:00
/* finally free the halfedges */
halfedge_free(d);
halfedge_free(orig_pair);
}
/*
* pass through all the halfedges on the left side and validate them
*/
static halfedge_t* del_valid_left( halfedge_t* b )
{
2014-12-21 11:56:31 +01:00
point2d_t *g, *d, *u, *v;
halfedge_t *c, *du, *dg;
g = b->vertex; /* base halfedge point */
dg = b;
d = b->pair->vertex; /* pair(halfedge) point */
b = b->next;
u = b->pair->vertex; /* next(pair(halfedge)) point */
du = b->pair;
v = b->next->pair->vertex; /* pair(next(next(halfedge)) point */
if( classify_point_seg(g, d, u) == ON_LEFT )
{
/* 3 points aren't colinear */
/* as long as the 4 points belong to the same circle, do the cleaning */
assert( v != u && "1: floating point precision error");
while( v != d && v != g && in_circle(g, d, u, v) == INSIDE )
{
c = b->next;
du = b->next->pair;
del_remove_edge(b);
b = c;
u = du->vertex;
v = b->next->pair->vertex;
}
assert( v != u && "2: floating point precision error");
if( v != d && v != g && in_circle(g, d, u, v) == ON_CIRCLE )
{
du = du->prev;
del_remove_edge(b);
}
} else /* treat the case where the 3 points are colinear */
du = dg;
assert(du->pair);
return du;
}
/*
* pass through all the halfedges on the right side and validate them
*/
static halfedge_t* del_valid_right( halfedge_t *b )
{
2014-12-21 11:56:31 +01:00
point2d_t *rv, *lv, *u, *v;
halfedge_t *c, *dd, *du;
b = b->pair;
rv = b->vertex;
dd = b;
lv = b->pair->vertex;
b = b->prev;
u = b->pair->vertex;
du = b->pair;
v = b->prev->pair->vertex;
if( classify_point_seg(lv, rv, u) == ON_LEFT )
{
assert( v != u && "1: floating point precision error");
while( v != lv && v != rv && in_circle(lv, rv, u, v) == INSIDE )
{
c = b->prev;
du = c->pair;
del_remove_edge(b);
b = c;
u = du->vertex;
v = b->prev->pair->vertex;
}
assert( v != u && "1: floating point precision error");
if( v != lv && v != rv && in_circle(lv, rv, u, v) == ON_CIRCLE )
{
du = du->next;
del_remove_edge(b);
}
} else
du = dd;
assert(du->pair);
return du;
}
/*
* validate a link
*/
static halfedge_t* del_valid_link( halfedge_t *b )
{
2014-12-21 11:56:31 +01:00
point2d_t *g, *g_p, *d, *d_p;
halfedge_t *gd, *dd, *new_gd, *new_dd;
g = b->vertex;
gd = del_valid_left(b);
g_p = gd->vertex;
assert(b->pair);
d = b->pair->vertex;
dd = del_valid_right(b);
d_p = dd->vertex;
assert(b->pair);
if( g != g_p && d != d_p )
{
int a = in_circle(g, d, g_p, d_p);
2014-12-21 11:56:31 +01:00
if( a != ON_CIRCLE )
{
if( a == INSIDE )
{
2022-08-08 14:25:14 +02:00
// cppcheck-suppress unreadVariable
2014-12-21 11:56:31 +01:00
g_p = g;
gd = b;
}
else
{
2022-08-08 14:25:14 +02:00
// cppcheck-suppress unreadVariable
2014-12-21 11:56:31 +01:00
d_p = d;
dd = b->pair;
}
}
}
/* create the 2 halfedges */
new_gd = halfedge_alloc();
new_dd = halfedge_alloc();
/* setup new_gd and new_dd */
new_gd->vertex = gd->vertex;
new_gd->pair = new_dd;
new_gd->prev = gd;
new_gd->next = gd->next;
gd->next->prev = new_gd;
gd->next = new_gd;
new_dd->vertex = dd->vertex;
new_dd->pair = new_gd;
new_dd->prev = dd->prev;
dd->prev->next = new_dd;
new_dd->next = dd;
dd->prev = new_dd;
return new_gd;
}
/*
* find the lower tangent between the two delaunay, going from left to right (returns the left half edge)
*/
static halfedge_t* del_get_lower_tangent( delaunay_t *left, delaunay_t *right )
{
2014-12-21 11:56:31 +01:00
halfedge_t *right_d, *left_d, *new_ld, *new_rd;
int sl, sr;
left_d = left->rightmost_he;
right_d = right->leftmost_he;
do {
point2d_t *pl = left_d->prev->pair->vertex;
point2d_t *pr = right_d->pair->vertex;
2014-12-21 11:56:31 +01:00
if( (sl = classify_point_seg(left_d->vertex, right_d->vertex, pl)) == ON_RIGHT ) {
left_d = left_d->prev->pair;
}
if( (sr = classify_point_seg(left_d->vertex, right_d->vertex, pr)) == ON_RIGHT ) {
right_d = right_d->pair->next;
}
} while( sl == ON_RIGHT || sr == ON_RIGHT );
/* create the 2 halfedges */
new_ld = halfedge_alloc();
new_rd = halfedge_alloc();
/* setup new_gd and new_dd */
new_ld->vertex = left_d->vertex;
new_ld->pair = new_rd;
new_ld->prev = left_d->prev;
left_d->prev->next = new_ld;
new_ld->next = left_d;
left_d->prev = new_ld;
new_rd->vertex = right_d->vertex;
new_rd->pair = new_ld;
new_rd->prev = right_d->prev;
right_d->prev->next = new_rd;
new_rd->next = right_d;
right_d->prev = new_rd;
return new_ld;
}
/*
* link the 2 delaunay together
*/
static void del_link( delaunay_t *result, delaunay_t *left, delaunay_t *right )
{
2014-12-21 11:56:31 +01:00
point2d_t *u, *v, *ml, *mr;
halfedge_t *base;
2014-12-21 11:56:31 +01:00
assert( left->points == right->points );
2014-12-21 11:56:31 +01:00
/* save the most right point and the most left point */
ml = left->leftmost_he->vertex;
mr = right->rightmost_he->vertex;
2014-12-21 11:56:31 +01:00
base = del_get_lower_tangent(left, right);
2014-12-21 11:56:31 +01:00
u = base->next->pair->vertex;
v = base->pair->prev->pair->vertex;
2014-12-21 11:56:31 +01:00
while( del_classify_point(base, u) == ON_LEFT ||
del_classify_point(base, v) == ON_LEFT )
{
base = del_valid_link(base);
u = base->next->pair->vertex;
v = base->pair->prev->pair->vertex;
}
2014-12-21 11:56:31 +01:00
right->rightmost_he = mr->he;
left->leftmost_he = ml->he;
2014-12-21 11:56:31 +01:00
/* TODO: this part is not needed, and can be optimized */
while( del_classify_point( right->rightmost_he, right->rightmost_he->prev->pair->vertex ) == ON_RIGHT )
right->rightmost_he = right->rightmost_he->prev;
2014-12-21 11:56:31 +01:00
while( del_classify_point( left->leftmost_he, left->leftmost_he->prev->pair->vertex ) == ON_RIGHT )
left->leftmost_he = left->leftmost_he->prev;
2014-12-21 11:56:31 +01:00
result->leftmost_he = left->leftmost_he;
result->rightmost_he = right->rightmost_he;
result->points = left->points;
result->start_point = left->start_point;
result->end_point = right->end_point;
}
/*
* divide and conquer delaunay
*/
void del_divide_and_conquer( delaunay_t *del, int start, int end );
void del_divide_and_conquer( delaunay_t *del, int start, int end )
{
2014-12-21 11:56:31 +01:00
delaunay_t left, right;
int n = (end - start + 1);
2014-12-21 11:56:31 +01:00
if( n > 3 )
{
int i = (n / 2) + (n & 1);
2014-12-21 11:56:31 +01:00
left.points = del->points;
right.points = del->points;
del_divide_and_conquer( &left, start, start + i - 1 );
del_divide_and_conquer( &right, start + i, end );
del_link( del, &left, &right );
} else
if( n == 3 )
del_init_tri( del, start );
else
if( n == 2 )
del_init_seg( del, start );
}
static void build_halfedge_face( delaunay_t *del, halfedge_t *d )
{
2014-12-21 11:56:31 +01:00
halfedge_t *curr;
2014-12-21 11:56:31 +01:00
/* test if the halfedge has already a pointing face */
2017-07-05 18:35:34 +02:00
if( d->face != nullptr )
2014-12-21 11:56:31 +01:00
return;
2014-12-21 11:56:31 +01:00
del->faces = (face_t*)realloc(del->faces, (del->num_faces + 1) * sizeof(face_t));
2014-12-21 11:56:31 +01:00
face_t *f = &(del->faces[del->num_faces]);
curr = d;
f->he = d;
f->num_verts = 0;
do {
curr->face = f;
(f->num_verts)++;
curr = curr->pair->prev;
} while( curr != d );
2014-12-21 11:56:31 +01:00
(del->num_faces)++;
/* if( d->face.radius < 0.0 )
2014-12-21 11:56:31 +01:00
{
d->face.p[0] = d->vertex;
d->face.p[1] = d->pair->vertex;
d->face.p[2] = d->pair->prev->pair->vertex;
if( classify_point_seg( d->face.p[0], d->face.p[1], d->face.p[2] ) == ON_LEFT )
{
compute_circle(d->face.p[0], d->face.p[1], d->face.p[2], &(d->face.cx), &(d->face.cy), &(d->face.radius));
}
}
*/
}
/*
* build the faces for all the halfedge
*/
void del_build_faces( delaunay_t *del );
void del_build_faces( delaunay_t *del )
{
quint32 i;
2014-12-21 11:56:31 +01:00
halfedge_t *curr;
2014-12-21 11:56:31 +01:00
del->num_faces = 0;
2017-07-05 18:35:34 +02:00
del->faces = nullptr;
2014-12-21 11:56:31 +01:00
/* build external face first */
build_halfedge_face(del, del->rightmost_he->pair);
2014-12-21 11:56:31 +01:00
for( i = del->start_point; i <= del->end_point; i++ )
{
curr = del->points[i]->he;
2014-12-21 11:56:31 +01:00
do {
build_halfedge_face( del, curr );
curr = curr->next;
} while( curr != del->points[i]->he );
}
}
/*
*/
delaunay2d_t* delaunay2d_from(del_point2d_t *points, quint32 num_points) {
2017-07-05 18:35:34 +02:00
delaunay2d_t* res = nullptr;
2014-12-21 11:56:31 +01:00
delaunay_t del;
quint32 i;
2017-07-05 18:35:34 +02:00
quint32* faces = nullptr;
del.num_faces = 0; //Warning using uninitialized value
#if PREDICATE == EXACT_PREDICATE
2014-12-21 11:56:31 +01:00
exactinit();
#endif
2014-12-21 11:56:31 +01:00
/* allocate the points */
del.points = (point2d_t**)malloc(num_points * sizeof(point2d_t*));
2017-07-05 18:35:34 +02:00
assert( del.points != nullptr );
2014-12-21 11:56:31 +01:00
memset(del.points, 0, num_points * sizeof(point2d_t*));
2014-12-21 11:56:31 +01:00
/* copy the points */
for( i = 0; i < num_points; i++ )
{
del.points[i] = point_alloc();
del.points[i]->idx = i;
del.points[i]->x = points[i].x;
del.points[i]->y = points[i].y;
}
2014-12-21 11:56:31 +01:00
qsort(del.points, num_points, sizeof(point2d_t*), cmp_points);
2014-12-21 11:56:31 +01:00
if( num_points >= 3 ) {
quint32 fbuff_size = 0;
quint32 j = 0;
del_divide_and_conquer( &del, 0, static_cast<int>(num_points - 1) );
2014-12-21 11:56:31 +01:00
del_build_faces( &del );
2014-12-21 11:56:31 +01:00
for( i = 0; i < del.num_faces; i++ )
fbuff_size += del.faces[i].num_verts + 1;
faces = (quint32*)malloc(sizeof(quint32) * fbuff_size);
2014-12-21 11:56:31 +01:00
for( i = 0; i < del.num_faces; i++ )
{
halfedge_t *curr;
2014-12-21 11:56:31 +01:00
faces[j] = del.faces[i].num_verts;
j++;
2014-12-21 11:56:31 +01:00
curr = del.faces[i].he;
do {
faces[j] = curr->vertex->idx;
j++;
curr = curr->pair->prev;
} while( curr != del.faces[i].he );
}
2014-12-21 11:56:31 +01:00
del_free_halfedges( &del );
2014-12-21 11:56:31 +01:00
free(del.faces);
for( i = 0; i < num_points; i++ )
point_free(del.points[i]);
2014-12-21 11:56:31 +01:00
free(del.points);
}
2014-12-21 11:56:31 +01:00
res = (delaunay2d_t*)malloc(sizeof(delaunay2d_t));
res->num_points = num_points;
res->points = (del_point2d_t*)malloc(sizeof(del_point2d_t) * num_points);
2014-12-21 11:56:31 +01:00
memcpy(res->points, points, sizeof(del_point2d_t) * num_points);
res->num_faces = del.num_faces;
res->faces = faces;
2014-12-21 11:56:31 +01:00
return res;
}
void delaunay2d_release(delaunay2d_t *del) {
2014-12-21 11:56:31 +01:00
free(del->faces);
free(del->points);
free(del);
}
QT_WARNING_POP