3932cf07e5
- in Triangulate aggiunta triangolazione Delaunay - aggiunti file della libreria TrianglePP - funzioni per polylines spostate da SurfTriMeshBooleans.cpp a PolyLine.cpp.
1455 lines
37 KiB
C++
1455 lines
37 KiB
C++
/*! \file tpp_impl.cpp
|
|
\brief The implementation of the 2D delaunay triangulation class.
|
|
|
|
This class is a wrapper on the triangle package.
|
|
*/
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
#include <iostream>
|
|
// changed mrkkrj --
|
|
//#include <triangle_impl.hpp>
|
|
//#include <tpp_interface.hpp>
|
|
|
|
// configuaration of the Triangle.h code:
|
|
#define NO_TIMER
|
|
#define DREDUCED
|
|
#define ANSI_DECLARATORS
|
|
#define TRILIBRARY
|
|
//#define CDT_ONLY // no, we want all algorithms!
|
|
|
|
#ifndef _WIN64
|
|
// the MS x64 compilers do not use FPU (as SSE is the default) thus no extended precision problems!
|
|
# define CPU86
|
|
#endif
|
|
|
|
// mrkkrj::: DEBUG trace
|
|
// - needed when debugging a GUI app. on Windows without console
|
|
|
|
//#define TRIANGLE_DBG_TO_FILE 1
|
|
|
|
#ifdef TRIANGLE_DBG_TO_FILE
|
|
# include <cstdio>
|
|
|
|
FILE* g_debugFile = nullptr;
|
|
|
|
// TR string
|
|
# define TRACE(a) { if(g_debugFile) { fprintf(g_debugFile, "%s\n", a); fflush(g_debugFile); } }
|
|
// TR string + integer
|
|
# define TRACE2i(a,b) { if(g_debugFile) { fprintf(g_debugFile, "%s%d\n", a, b); fflush(g_debugFile); } }
|
|
// TR string + string
|
|
# define TRACE2s(a,b) { if(g_debugFile) { fprintf(g_debugFile, "%s%s\n", a, b); fflush(g_debugFile); } }
|
|
// TR string + boolean
|
|
# define TRACE2b(a,b) { if(g_debugFile) { fprintf(g_debugFile, "%s%s\n", a, b ? "true " : "false"); fflush(g_debugFile); } }
|
|
|
|
# define INIT_TRACE(a) { g_debugFile = fopen(a, "w"); \
|
|
if(!g_debugFile) std::cerr << "ERROR: Cannot open trace file: " << a << std::endl; }
|
|
# define END_TRACE() { if(g_debugFile) { fclose(g_debugFile); } }
|
|
#else
|
|
# define TRACE(a)
|
|
# define TRACE2i(a,b)
|
|
# define TRACE2s(a,b)
|
|
# define TRACE2b(a,b)
|
|
# define INIT_TRACE(a)
|
|
# define END_TRACE()
|
|
#endif
|
|
|
|
#define TRIANGLE_DETAIL_DEBUG 0
|
|
|
|
// end DEBUG trace (mrkkrj)
|
|
|
|
|
|
#include "triangle_impl.hpp"
|
|
#include "tpp_interface.hpp"
|
|
#include <sstream>
|
|
#include <cassert>
|
|
#include <algorithm>
|
|
// END changed --
|
|
|
|
#include <new>
|
|
|
|
#define REAL double
|
|
|
|
|
|
namespace tpp {
|
|
|
|
using std::cout;
|
|
using std::cerr;
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::Delaunay(const std::vector<Point>& points)
|
|
: m_in(nullptr),
|
|
m_triangleWrap(nullptr),
|
|
m_pmesh(nullptr),
|
|
m_pbehavior(nullptr),
|
|
m_Triangulated(false),
|
|
m_vorout(nullptr),
|
|
m_minAngle(0.0f),
|
|
m_maxArea(0.0f)
|
|
{
|
|
m_PList.assign(points.begin(), points.end());
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::~Delaunay() {
|
|
freeTriangleDataStructs();
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void Delaunay::Triangulate(bool quality, DebugOutputLevel traceLvl) {
|
|
std::string options = "nz"; // n: need neighbors, z: index from 0
|
|
|
|
if (quality) {
|
|
options.append("q");
|
|
if (m_minAngle > 0) {
|
|
options.append(formatFloatConstraint(m_minAngle));
|
|
}
|
|
if (m_maxArea > 0) {
|
|
options.append("a" + formatFloatConstraint(m_maxArea));
|
|
}
|
|
}
|
|
|
|
// non devono essere aggiunti Steiner points sul contorno
|
|
options.append( "YY") ;
|
|
|
|
setDebugLevelOption(options, traceLvl);
|
|
|
|
Triangulate(options);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void Delaunay::TriangulateConf( bool quality, DebugOutputLevel traceLvl) {
|
|
std::string options = "nz"; // n: need neighbors, z: index from 0
|
|
|
|
options.append("D"); // conforming Delaunay!
|
|
setDebugLevelOption(options, traceLvl);
|
|
|
|
if (quality) {
|
|
options.append("q");
|
|
if (m_minAngle > 0) {
|
|
options.append(formatFloatConstraint(m_minAngle));
|
|
}
|
|
if (m_maxArea > 0) {
|
|
options.append("a" + formatFloatConstraint(m_maxArea));
|
|
}
|
|
}
|
|
|
|
// non devono essere aggiunti Steiner points sul contorno
|
|
options.append("YY");
|
|
|
|
Triangulate(options);
|
|
}
|
|
|
|
/*!
|
|
Triangulate the points stored in m_PList.
|
|
\note (mrkkrj) copy-pasted from parts of the original Triangle's triangulate() function!
|
|
\author Piyush Kumar (originally),
|
|
mrkkrj (extracted it, debug output to file, corections, extensions)
|
|
*/
|
|
void Delaunay::Triangulate(std::string& triswitches) {
|
|
INIT_TRACE("triangle.out.txt");
|
|
TRACE("Triangulate ->");
|
|
|
|
if (m_Triangulated) {
|
|
freeTriangleDataStructs();
|
|
}
|
|
|
|
#if TRIANGLE_DETAIL_DEBUG
|
|
size_t posV = triswitches.find("V");
|
|
if(posV != std::string::npos) {
|
|
triswitches.insert(posV, "V"); // detailed trace!
|
|
}
|
|
#endif
|
|
|
|
m_in = new triangulateio;
|
|
triangulateio* pin = (struct triangulateio *)m_in;
|
|
|
|
pin->numberofpoints = (int)m_PList.size();
|
|
pin->numberofpointattributes = (int)0;
|
|
pin->pointlist = static_cast<double *>((void *)(&m_PList[0]));
|
|
pin->pointattributelist = nullptr;
|
|
pin->pointmarkerlist = /*(int *) */nullptr;
|
|
pin->numberofsegments = 0;
|
|
pin->numberofholes = 0;
|
|
pin->numberofregions = 0;
|
|
pin->regionlist = /*(REAL *)*/ nullptr;
|
|
|
|
if (!m_SList.empty()) // OPEN:: a separate option to enable segment constraitns???
|
|
{
|
|
pin->numberofsegments = (int)m_SList.size() / 2;
|
|
pin->segmentlist = m_SList.data();
|
|
pin->segmentmarkerlist = nullptr;
|
|
|
|
triswitches.append("p"); // constrained Delaunay (Planar Straight Line Graph)
|
|
triswitches.append("B"); // but no boundary info at the moment!
|
|
triswitches.append("c"); // -c Encloses the convex hull with segments - (preserve bounaries in carveholes())
|
|
}
|
|
|
|
if (!m_HList.empty()) // OPEN:: a separate option to enable carving of holes???
|
|
{
|
|
pin->numberofholes = (int)m_HList.size();
|
|
pin->holelist = static_cast<double*>((void*)(&m_HList[0]));
|
|
|
|
//triswitches.append("???");
|
|
if (m_SList.empty())
|
|
{
|
|
triswitches.append("p"); // constrained Delaunay (Planar Straight Line Graph)
|
|
triswitches.append("B"); // but no boundary info at the moment!
|
|
triswitches.append("c"); // -c Encloses the convex hull with segments - (preserve bounaries in carveholes())
|
|
}
|
|
}
|
|
|
|
m_triangleWrap = new Triwrap;
|
|
Triwrap* pTriangleWrap = (Triwrap *)m_triangleWrap;
|
|
triswitches.push_back('\0');
|
|
char *pTriswitches = &triswitches[0];
|
|
|
|
m_pmesh = new Triwrap::__pmesh;
|
|
m_pbehavior = new Triwrap::__pbehavior;
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
Triwrap::__pbehavior * tpbehavior = (Triwrap::__pbehavior *) m_pbehavior;
|
|
|
|
// parse the options:
|
|
pTriangleWrap->parsecommandline(1, &pTriswitches, tpbehavior);
|
|
|
|
// initialize data structs
|
|
pTriangleWrap->triangleinit(tpmesh);
|
|
tpmesh->steinerleft = tpbehavior->steiner; // added mrkkrj
|
|
|
|
pTriangleWrap->transfernodes(
|
|
tpmesh, tpbehavior, pin->pointlist,
|
|
pin->pointattributelist,
|
|
pin->pointmarkerlist, pin->numberofpoints,
|
|
pin->numberofpointattributes);
|
|
|
|
// triangulate!
|
|
tpmesh->hullsize = pTriangleWrap->delaunay(tpmesh, tpbehavior);
|
|
|
|
// OPEN TODO:: mrkkrj
|
|
// if(concave hull) - compute concave hull with the chi-algorithm,
|
|
// - use it as segments in formskeleton()!!
|
|
// end TODO::
|
|
|
|
// Ensure that no vertex can be mistaken for a triangular bounding
|
|
// box vertex in insertvertex().
|
|
tpmesh->infvertex1 = nullptr;
|
|
tpmesh->infvertex2 = nullptr;
|
|
tpmesh->infvertex3 = nullptr;
|
|
|
|
// added mrkkrj: support for the "-q" option
|
|
if (tpbehavior->usesegments && (tpmesh->triangles.items > 0)) {
|
|
tpmesh->checksegments = 1; /* Segments will be introduced next. */
|
|
if (!tpbehavior->refine) {
|
|
/* Insert PSLG segments and/or convex hull segments. */
|
|
pTriangleWrap->formskeleton(tpmesh, tpbehavior, pin->segmentlist,
|
|
pin->segmentmarkerlist, pin->numberofsegments);
|
|
}
|
|
}
|
|
|
|
if (tpbehavior->quality && (tpmesh->triangles.items > 0)) {
|
|
pTriangleWrap->enforcequality(tpmesh, tpbehavior); /* Enforce angle and area constraints. */
|
|
}
|
|
|
|
//#if 0 -> mrkkrj
|
|
if (tpbehavior->poly && (tpmesh->triangles.items > 0)) {
|
|
/*tpmesh->holes = 0;
|
|
tpmesh->regions = 0;*/
|
|
|
|
// mrkkrj
|
|
tpmesh->holes = pin->numberofholes;
|
|
double* holelist = pin->holelist;
|
|
|
|
tpmesh->regions = 0;
|
|
double* regionlist = nullptr; // not yet supported
|
|
|
|
if (!tpbehavior->refine) {
|
|
/* Carve out holes and concavities. */
|
|
pTriangleWrap->carveholes(tpmesh, tpbehavior, holelist, tpmesh->holes, regionlist, tpmesh->regions);
|
|
}
|
|
}
|
|
//#endif
|
|
|
|
|
|
|
|
/* Calculate the number of edges. */
|
|
tpmesh->edges = (3l * tpmesh->triangles.items + tpmesh->hullsize) / 2l;
|
|
pTriangleWrap->numbernodes(tpmesh, tpbehavior);
|
|
TRACE2i("<- Triangulate: triangles= ", tpmesh->triangles.items);
|
|
|
|
m_Triangulated = true;
|
|
END_TRACE();
|
|
}
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
void Delaunay::Tesselate(bool useConformingDelaunay, DebugOutputLevel traceLvl) {
|
|
std::string options = "nz"; // n: need neighbors, z: index from 0
|
|
setDebugLevelOption(options, traceLvl);
|
|
|
|
// "If the triangulated domain is"
|
|
//" convex and has no holes, you can use -D switch to force Triangle to"
|
|
//" construct a conforming Delaunay triangulation instead of a CCDT, so the"
|
|
//" Voronoi diagram will be valid."
|
|
|
|
//options.append("D"); // Voronoi precondition ??? not really!!!
|
|
if (useConformingDelaunay)
|
|
{
|
|
// an option for experimenting!
|
|
options.append("D");
|
|
}
|
|
options.append("v"); // Voronoi
|
|
|
|
Triangulate(options);
|
|
|
|
// now use the triangulation for a Voronoi diagram
|
|
Triwrap* pTriangleWrap = (Triwrap*)m_triangleWrap;
|
|
|
|
Triwrap::__pmesh* tpmesh = (Triwrap::__pmesh*) m_pmesh;
|
|
Triwrap::__pbehavior* tpbehavior = (Triwrap::__pbehavior*) m_pbehavior;
|
|
|
|
// OPEN TODO::: check these preconditions??
|
|
if (tpmesh->holes != 0) {
|
|
|
|
}
|
|
|
|
m_vorout = new triangulateio;
|
|
triangulateio* pvorout = (struct triangulateio*)m_vorout;
|
|
|
|
pvorout->numberofpoints = tpmesh->triangles.items;
|
|
pvorout->numberofpointattributes = tpmesh->nextras;
|
|
pvorout->numberofedges = tpmesh->edges;
|
|
|
|
pvorout->pointlist = nullptr;
|
|
pvorout->pointattributelist = nullptr;
|
|
pvorout->pointmarkerlist = nullptr;
|
|
pvorout->numberofsegments = 0;
|
|
pvorout->numberofholes = 0;
|
|
pvorout->numberofregions = 0;
|
|
pvorout->regionlist = nullptr;
|
|
pvorout->edgelist = nullptr;
|
|
pvorout->edgemarkerlist = nullptr;
|
|
pvorout->normlist = nullptr;
|
|
|
|
pTriangleWrap->writevoronoi(
|
|
tpmesh, tpbehavior,
|
|
&pvorout->pointlist, &pvorout->pointattributelist,
|
|
&pvorout->pointmarkerlist, &pvorout->edgelist,
|
|
&pvorout->edgemarkerlist, &pvorout->normlist);
|
|
}
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
bool Delaunay::checkConstraints(bool& possible) const
|
|
{
|
|
//" If the minimum angle is 28.6"
|
|
//" degrees or smaller, Triangle is mathematically guaranteed to"
|
|
//" terminate (assuming infinite precision arithmetic--Triangle may"
|
|
//" fail to terminate if you run out of precision). In practice,"
|
|
//" Triangle often succeeds for minimum angles up to 34 degrees. For"
|
|
//" some meshes, however, you might need to reduce the minimum angle to"
|
|
//" avoid problems associated with insufficient floating-point"
|
|
//" precision."
|
|
if (m_minAngle <= 28.6)
|
|
{
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
possible = (m_minAngle <= 34.0);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
bool Delaunay::checkConstraintsOpt(bool relaxed) const
|
|
{
|
|
bool possible = false;
|
|
bool ret = checkConstraints(possible);
|
|
|
|
if (!ret && relaxed)
|
|
{
|
|
return possible;
|
|
}
|
|
else
|
|
{
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
void Delaunay::getMinAngleBoundaries(float& guaranteed, float& possible)
|
|
{
|
|
// see above:
|
|
guaranteed = 28.6f;
|
|
possible = 34.0f;
|
|
}
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
bool Delaunay::setSegmentConstraint(const std::vector<Point>& segments)
|
|
{
|
|
m_SList.clear();
|
|
m_SList.reserve(segments.size());
|
|
|
|
// OPEN TODO::: optimize - unquadrat it...
|
|
for (size_t i = 0; i < segments.size(); ++i)
|
|
{
|
|
const std::vector<Point>::iterator it = std::find(m_PList.begin(), m_PList.end(), segments[i]);
|
|
if (it == m_PList.end())
|
|
{
|
|
m_SList.clear();
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
m_SList.push_back(std::distance(m_PList.begin(), it));
|
|
}
|
|
}
|
|
|
|
// OPEN TODO::: check the intersection constraints ...
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
bool Delaunay::setSegmentConstraint(const std::vector<int>& segmentPointIndexes)
|
|
{
|
|
m_SList.clear();
|
|
m_SList.reserve(segmentPointIndexes.size());
|
|
|
|
for (size_t i = 0; i < segmentPointIndexes.size(); ++i)
|
|
{
|
|
const int& pointIdx = segmentPointIndexes[i];
|
|
if (pointIdx < 0 ||
|
|
pointIdx >= m_PList.size())
|
|
{
|
|
m_SList.clear();
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
m_SList.push_back(pointIdx);
|
|
}
|
|
}
|
|
|
|
// OPEN TODO::: check for intersections!!!!
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
bool Delaunay::setHolesConstraint(const std::vector<Point>& holes)
|
|
{
|
|
m_HList = holes;
|
|
|
|
// OPEN TODO::: check the intersection constraints ...
|
|
|
|
// TEST::: make them also points!!
|
|
//m_PList.insert(m_PList.end(), holes.begin(), holes.end());
|
|
|
|
// ???
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
/*!
|
|
*/
|
|
void Delaunay::writeoff(std::string& fname){
|
|
if(!m_Triangulated) {
|
|
cerr << "FATAL: Write called before triangulation\n";
|
|
//exit(1);
|
|
throw std::runtime_error("FATAL: Write called before triangulation");
|
|
}
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
Triwrap::__pbehavior * tpbehavior = (Triwrap::__pbehavior *) m_pbehavior;
|
|
|
|
Triwrap *pTriangleWrap = (Triwrap *)m_triangleWrap;
|
|
char *pfname = new char[fname.size()+1];
|
|
strcpy(pfname , fname.c_str());
|
|
|
|
pTriangleWrap->writeoff(tpmesh, tpbehavior, pfname, 0, nullptr);
|
|
delete [] pfname;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::nedges() const {
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
return tpmesh->edges;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::ntriangles() const {
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
return tpmesh->triangles.items;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::nvertices() const {
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
Triwrap::__pbehavior * tpbehavior = (Triwrap::__pbehavior *) m_pbehavior;
|
|
int outvertices;
|
|
|
|
if (tpbehavior->jettison) {
|
|
outvertices = tpmesh->vertices.items - tpmesh->undeads;
|
|
} else {
|
|
outvertices = tpmesh->vertices.items;
|
|
}
|
|
|
|
return outvertices;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::hull_size() const {
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
return tpmesh->hullsize;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::vertexId(vIterator const &vit) const {
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) vit.MyDelaunay->m_pmesh;
|
|
return ((int *)vit.vloop)[tpmesh->vertexmarkindex];
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::nvedges() const {
|
|
triangulateio* pvorout = (struct triangulateio*)m_vorout;
|
|
if (!pvorout) {
|
|
return 0;
|
|
}
|
|
else {
|
|
return pvorout->numberofedges;
|
|
}
|
|
}
|
|
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::nvpoints() const {
|
|
triangulateio* pvorout = (struct triangulateio*)m_vorout;
|
|
if (!pvorout) {
|
|
return 0;
|
|
}
|
|
else {
|
|
return pvorout->numberofpoints;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
std::string Delaunay::formatFloatConstraint(float f) const {
|
|
std::ostringstream ss;
|
|
ss << f;
|
|
return ss.str();
|
|
}
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
void Delaunay::setDebugLevelOption(std::string& options, DebugOutputLevel traceLvl) {
|
|
switch (traceLvl) {
|
|
case None:
|
|
options.append("Q"); // Q: no trace, no debug
|
|
break;
|
|
case Info:
|
|
options.append("V"); // trace & debug
|
|
break;
|
|
case Vertex:
|
|
options.append("VV"); // more trace & debug
|
|
break;
|
|
case Debug:
|
|
options.append("VVVV"); // much, much more!
|
|
break;
|
|
default:
|
|
assert(false && "unknown trace level");
|
|
}
|
|
}
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
void Delaunay::freeTriangleDataStructs()
|
|
{
|
|
struct triangulateio* pin = (struct triangulateio*) m_in;
|
|
struct triangulateio* pvorout = (struct triangulateio*) m_vorout;
|
|
|
|
Triwrap* pTriangleWrap = (Triwrap*)m_triangleWrap;
|
|
|
|
Triwrap::__pmesh* tpmesh = (Triwrap::__pmesh*) m_pmesh;
|
|
Triwrap::__pbehavior* tpbehavior = (Triwrap::__pbehavior*) m_pbehavior;
|
|
|
|
pTriangleWrap->triangledeinit(tpmesh, tpbehavior);
|
|
|
|
delete tpmesh;
|
|
delete tpbehavior;
|
|
delete pin;
|
|
delete pvorout;
|
|
delete pTriangleWrap;
|
|
|
|
m_in = nullptr;
|
|
m_vorout = nullptr;
|
|
m_triangleWrap = nullptr;
|
|
m_pmesh = nullptr;
|
|
m_pbehavior = nullptr;
|
|
|
|
}
|
|
|
|
///////////////////////////////
|
|
//
|
|
// Vertex Iterator Impl.
|
|
//
|
|
///////////////////////////////
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::vIterator::vIterator(Delaunay* triangulator) {
|
|
typedef Triwrap::vertex vertex;
|
|
MyDelaunay = triangulator;
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) triangulator->m_pmesh;
|
|
Triwrap::__pbehavior * tpbehavior = (Triwrap::__pbehavior *) triangulator->m_pbehavior;
|
|
Triwrap *pTriangleWrap = (Triwrap *) triangulator->m_triangleWrap;
|
|
|
|
pTriangleWrap->traversalinit(&( tpmesh->vertices ) );
|
|
vloop = pTriangleWrap->vertextraverse(tpmesh);
|
|
|
|
while
|
|
(
|
|
tpbehavior->jettison ||
|
|
(
|
|
((int *)vloop)[tpmesh->vertexmarkindex+1] == UNDEADVERTEX
|
|
)
|
|
)
|
|
vloop = (void *) pTriangleWrap->vertextraverse(tpmesh);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::vIterator::~vIterator(){
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::vIterator Delaunay::vend(){
|
|
vIterator vit;
|
|
vit.vloop = ((Triwrap::vertex) nullptr);
|
|
return vit;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::vIterator Delaunay::vIterator::operator++() {
|
|
typedef Triwrap::vertex vertex;
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) MyDelaunay->m_pmesh;
|
|
Triwrap::__pbehavior * tpbehavior =
|
|
(Triwrap::__pbehavior *) MyDelaunay->m_pbehavior;
|
|
|
|
Triwrap *pTriangleWrap = (Triwrap *) MyDelaunay->m_triangleWrap;
|
|
|
|
while
|
|
(
|
|
tpbehavior->jettison ||
|
|
(
|
|
((int *)vloop)[tpmesh->vertexmarkindex+1] == UNDEADVERTEX
|
|
)
|
|
)
|
|
vloop = (void *) pTriangleWrap->vertextraverse(tpmesh);
|
|
vloop = (void *) pTriangleWrap->vertextraverse(tpmesh);
|
|
|
|
vIterator vit;
|
|
vit.vloop = vloop;
|
|
vit.MyDelaunay = MyDelaunay;
|
|
|
|
return vit;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::Point & Delaunay::vIterator::operator*() const{
|
|
return *((Point *)vloop);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool operator==(Delaunay::vIterator const &vit1,
|
|
Delaunay::vIterator const &vit2) {
|
|
if (vit1.vloop == vit2.vloop) return true;
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool operator!=(Delaunay::vIterator const &vit1,
|
|
Delaunay::vIterator const &vit2) {
|
|
if (vit1.vloop != vit2.vloop) return true;
|
|
return false;
|
|
}
|
|
|
|
|
|
///////////////////////////////
|
|
//
|
|
// Face Iterator Impl.
|
|
//
|
|
///////////////////////////////
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::fIterator::fIterator(Delaunay* triangulator) {
|
|
typedef Triwrap::vertex vertex;
|
|
typedef Triwrap::__otriangle trianglelooptype; // oriented triangle
|
|
|
|
MyDelaunay = triangulator;
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) triangulator->m_pmesh;
|
|
Triwrap *pTriangleWrap = (Triwrap *)triangulator->m_triangleWrap;
|
|
|
|
pTriangleWrap->traversalinit(&( tpmesh->triangles ) );
|
|
// floop = new trianglelooptype;
|
|
trianglelooptype *ploop = (trianglelooptype *)(&floop);
|
|
ploop->tri = pTriangleWrap->triangletraverse(tpmesh);
|
|
ploop->orient = 0;
|
|
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::fIterator::~fIterator(){
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::fIterator Delaunay::fend(){
|
|
fIterator fit;
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
fit.floop.tri = (double ***) nullptr;
|
|
return fit;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void Delaunay::fIterator::operator++() {
|
|
// cout << "++ called\n";
|
|
typedef Triwrap::vertex vertex;
|
|
typedef Triwrap::triangle triangle;
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) MyDelaunay->m_pmesh;
|
|
|
|
trianglelooptype *ploop = (trianglelooptype *)(&floop);
|
|
Triwrap *pTriangleWrap = (Triwrap *) MyDelaunay->m_triangleWrap;
|
|
|
|
ploop->tri = pTriangleWrap->triangletraverse(tpmesh);
|
|
// cout << "tri val = " << ploop->tri << endl;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool operator==(Delaunay::fIterator const &fit1,
|
|
Delaunay::fIterator const &fit2) {
|
|
|
|
return (fit1.floop.tri == fit2.floop.tri);
|
|
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool operator!=(Delaunay::fIterator const &fit1,
|
|
Delaunay::fIterator const &fit2) {
|
|
return !( operator==(fit1,fit2) );
|
|
}
|
|
|
|
/*!
|
|
added mrkkrj:
|
|
*/
|
|
bool operator<(Delaunay::fIterator const &fit1,
|
|
Delaunay::fIterator const &fit2) {
|
|
return (fit1.floop.tri < fit2.floop.tri);
|
|
|
|
}
|
|
|
|
// 2 helpers for the following methods
|
|
// (added mrkkrj)
|
|
|
|
/*!
|
|
*/
|
|
void Delaunay::SetPoint(Point& point, /*Triwrap::vertex*/ double* vertexptr){
|
|
// OPEN TODO: compile test type check - Triwrap::vertex == double* ???
|
|
point[0] = (vertexptr)[0]; // x
|
|
point[1] = (vertexptr)[1]; // y
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::GetVertexIndex(fIterator const & fit, /*Triwrap::vertex*/ double* vertexptr){
|
|
// OPEN TODO: compile test type check - Triwrap::vertex == double* ???
|
|
Triwrap::__pbehavior * tpbehavior = (Triwrap::__pbehavior *)
|
|
((fit.MyDelaunay)->m_pbehavior);
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) (fit.MyDelaunay->m_pmesh);
|
|
|
|
int ret =
|
|
( ((int *) (vertexptr))[tpmesh->vertexmarkindex] )
|
|
-
|
|
tpbehavior->firstnumber;
|
|
|
|
return ((unsigned)ret < m_PList.size()) ? ret : -1;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::GetFirstIndexNumber() const {
|
|
Triwrap::__pbehavior* pbehavior = (Triwrap::__pbehavior*)m_pbehavior;
|
|
return pbehavior->firstnumber;
|
|
}
|
|
|
|
/*!
|
|
A triangle abc has origin (org) a, destination (dest) b, and apex (apex)
|
|
c. These vertices occur in counterclockwise order about the triangle.
|
|
*/
|
|
int Delaunay::Org(fIterator const & fit, Point* point){
|
|
typedef Triwrap::vertex vertex;
|
|
typedef Triwrap::triangle triangle;
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
|
|
trianglelooptype * ploop = (trianglelooptype *)(&(fit.floop));
|
|
|
|
vertex vertexptr = (vertex) ((ploop->tri)[plus1mod3[ploop->orient] + 3]);
|
|
|
|
if(point) SetPoint(*point, vertexptr);
|
|
return GetVertexIndex(fit, vertexptr);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::Dest(fIterator const & fit, Point* point){
|
|
typedef Triwrap::vertex vertex;
|
|
typedef Triwrap::triangle triangle;
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
|
|
trianglelooptype * ploop = (trianglelooptype *)(&(fit.floop));
|
|
|
|
vertex vertexptr = (vertex) ((ploop->tri)[minus1mod3[ploop->orient] + 3]);
|
|
|
|
if(point) SetPoint(*point, vertexptr);
|
|
return GetVertexIndex(fit, vertexptr);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::Apex(fIterator const & fit, Point* point){
|
|
typedef Triwrap::vertex vertex;
|
|
typedef Triwrap::triangle triangle;
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
|
|
trianglelooptype * ploop = (trianglelooptype *)(&(fit.floop));
|
|
|
|
vertex vertexptr = (vertex) ((ploop->tri)[ploop->orient + 3]);
|
|
|
|
if(point) SetPoint(*point, vertexptr);
|
|
return GetVertexIndex(fit, vertexptr);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::Sym(fIterator const & fit, char i){
|
|
typedef Triwrap::vertex vertex;
|
|
typedef Triwrap::triangle triangle;
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
triangle ptr; /* Temporary variable used by sym(). */
|
|
|
|
//Triwrap::__pbehavior * tpbehavior = (Triwrap::__pbehavior *)
|
|
// ((fit.MyDelaunay)->pbehavior);
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) (fit.MyDelaunay->m_pmesh);
|
|
trianglelooptype * ploop = (trianglelooptype *)(&(fit.floop));
|
|
|
|
char oval = (char)ploop->orient;
|
|
ploop->orient = i;
|
|
|
|
trianglelooptype top;
|
|
sym(*ploop, top);
|
|
ploop->orient = oval;
|
|
|
|
if(top.tri != tpmesh->dummytri){
|
|
vertex farvertex;
|
|
apex(top, farvertex);
|
|
return ((int *)farvertex)[tpmesh->vertexmarkindex];
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::fIterator Delaunay::Sym(fIterator const & fit){
|
|
fIterator retval;
|
|
retval.MyDelaunay = fit.MyDelaunay;
|
|
|
|
typedef Triwrap::vertex vertex;
|
|
typedef Triwrap::triangle triangle;
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
triangle ptr; /* Temporary variable used by sym(). */
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) (fit.MyDelaunay->m_pmesh);
|
|
trianglelooptype * ploop = (trianglelooptype *)(&(fit.floop));
|
|
|
|
|
|
trianglelooptype top;
|
|
sym(*ploop, top);
|
|
|
|
|
|
if(top.tri != tpmesh->dummytri){
|
|
retval.floop.tri = top.tri;
|
|
retval.floop.orient = top.orient;
|
|
|
|
return retval;
|
|
}
|
|
|
|
retval.floop.tri = nullptr;
|
|
retval.floop.orient = 0;
|
|
return retval;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
double Delaunay::area(fIterator const & fit){
|
|
Point torg, tdest, tapex;
|
|
torg = point_at_vertex_id(Org(fit));
|
|
tdest = point_at_vertex_id(Dest(fit));
|
|
tapex = point_at_vertex_id(Apex(fit));
|
|
double dxod(torg[0] - tdest[0]);
|
|
double dyod(torg[1] - tdest[1]);
|
|
double dxda(tdest[0] - tapex[0]);
|
|
double dyda(tdest[1] - tapex[1]);
|
|
|
|
double area = 0.5 * (dxod * dyda - dyod * dxda);
|
|
return area;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::fIterator Delaunay::locate(int vertexid){
|
|
fIterator retval;
|
|
retval.MyDelaunay = this;
|
|
|
|
typedef Triwrap::vertex vertex;
|
|
typedef Triwrap::triangle triangle;
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
|
|
trianglelooptype horiz; /* Temporary variable for use in locate(). */
|
|
triangle ptr; /* Temporary variable used by sym(). */
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
Triwrap::__pbehavior * tpbehavior = (Triwrap::__pbehavior *) m_pbehavior;
|
|
Triwrap *pTriangleWrap = (Triwrap *) m_triangleWrap;
|
|
|
|
horiz.tri = tpmesh->dummytri;
|
|
horiz.orient = 0;
|
|
symself(horiz);
|
|
double dv[2];
|
|
dv[0] = m_PList[vertexid][0];
|
|
dv[1] = m_PList[vertexid][1];
|
|
|
|
/* Search for a triangle containing `newvertex'. */
|
|
int intersect = pTriangleWrap->locate(tpmesh, tpbehavior, dv, &horiz);
|
|
Assert(intersect != Triwrap::ONVERTEX, "Something went wrong in point location\n"); // added mrkkrj
|
|
|
|
if(intersect != Triwrap::ONVERTEX) { // Not on vertex!
|
|
cout << "Something went wrong in point location\n";
|
|
exit(1);
|
|
}
|
|
|
|
retval.floop.tri = horiz.tri;
|
|
retval.floop.orient = horiz.orient;
|
|
|
|
return retval;
|
|
}
|
|
|
|
/*!
|
|
lnext() finds the next edge (counterclockwise) of a triangle.
|
|
*/
|
|
Delaunay::fIterator Delaunay::Lnext(fIterator const & fit){
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
|
|
fIterator retval;
|
|
retval.MyDelaunay = this;
|
|
|
|
lnext( (*(trianglelooptype *)(&(fit.floop))), (*(trianglelooptype *)(&(retval.floop))));
|
|
return retval;
|
|
}
|
|
|
|
/*!
|
|
lprev: Find the previous edge (clockwise) of a triangle.
|
|
lprev(abc) -> cab
|
|
*/
|
|
Delaunay::fIterator Delaunay::Lprev(fIterator const & fit){
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
|
|
fIterator retval;
|
|
retval.MyDelaunay = this;
|
|
|
|
lprev( (*(trianglelooptype *)(&(fit.floop))), (*(trianglelooptype *)(&(retval.floop))));
|
|
return retval;
|
|
}
|
|
|
|
/*!
|
|
onext: Find the next edge counterclockwise with the same origin.
|
|
onext(abc) -> ac*
|
|
*/
|
|
Delaunay::fIterator Delaunay::Onext(fIterator const & fit){
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
typedef Triwrap::triangle triangle;
|
|
|
|
triangle ptr;
|
|
fIterator retval;
|
|
retval.MyDelaunay = this;
|
|
|
|
//cout << "Onext called:\n "
|
|
// << Org(fit) << "\t" << Dest(fit) << "\t" << Apex(fit) << "\n";
|
|
|
|
onext( (*(trianglelooptype *)(&(fit.floop))), (*(trianglelooptype *)(&(retval.floop))));
|
|
|
|
// retval could be dummy!
|
|
return retval;
|
|
}
|
|
|
|
/*!
|
|
oprev: Find the next edge clockwise with the same origin.
|
|
oprev(abc) -> a*b
|
|
*/
|
|
Delaunay::fIterator Delaunay::Oprev(fIterator const & fit){
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
typedef Triwrap::triangle triangle;
|
|
|
|
triangle ptr;
|
|
fIterator retval;
|
|
retval.MyDelaunay = this;
|
|
|
|
oprev( (*(trianglelooptype *)(&(fit.floop))), (*(trianglelooptype *)(&(retval.floop))));
|
|
return retval;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool Delaunay::isdummy(fIterator const & fit){
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
typedef Triwrap::__otriangle trianglelooptype;
|
|
|
|
return ( ((trianglelooptype *)(&(fit.floop)))->tri == tpmesh->dummytri );
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void Delaunay::trianglesAroundVertex(int vertexid, std::vector<int>& ivv){
|
|
fIterator fit = locate(vertexid);
|
|
ivv.clear();
|
|
|
|
int start = Dest(fit);
|
|
int linkn = Apex(fit);
|
|
|
|
ivv.push_back(vertexid);
|
|
ivv.push_back(start);
|
|
ivv.push_back(linkn);
|
|
|
|
fIterator nfit = fit;
|
|
fIterator pnfit = fit; // follows nfit by one triangle
|
|
|
|
while( linkn != start ){
|
|
|
|
nfit = Onext(nfit);
|
|
if (isdummy(nfit)){
|
|
// Do another algorithm
|
|
ivv.clear();
|
|
|
|
// use oprev now...
|
|
fit = pnfit;
|
|
nfit = fit;
|
|
|
|
start = Apex(fit);
|
|
linkn = Dest(fit);
|
|
|
|
ivv.push_back(vertexid);
|
|
ivv.push_back(linkn);
|
|
ivv.push_back(start);
|
|
|
|
while( linkn != start ){
|
|
nfit = Oprev(nfit);
|
|
if(isdummy(nfit))
|
|
return;
|
|
int a = Org(nfit);
|
|
int b = Dest(nfit);
|
|
int c = Apex(nfit);
|
|
ivv.push_back(a);
|
|
ivv.push_back(b);
|
|
ivv.push_back(c);
|
|
linkn = Dest(nfit);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
pnfit = nfit;
|
|
|
|
int a = Org(nfit);
|
|
int b = Dest(nfit);
|
|
int c = Apex(nfit);
|
|
|
|
//cout << "Triangle: " << a << "\t" << b << "\t" << c << "\n";
|
|
|
|
ivv.push_back(a);
|
|
ivv.push_back(b);
|
|
ivv.push_back(c);
|
|
|
|
linkn = Apex(nfit);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
///////////////////////////////
|
|
//
|
|
// Voronoi Point Iterator Impl.
|
|
// (added mrkkrj)
|
|
//
|
|
///////////////////////////////
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::vvIterator::vvIterator()
|
|
: m_delaunay(nullptr), vvloop(nullptr), vvindex(0), vvcount(0) {
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::vvIterator::vvIterator(Delaunay* triangulator) {
|
|
m_delaunay = triangulator;
|
|
triangulateio* pvorout = (struct triangulateio*)triangulator->m_vorout;
|
|
|
|
// TEST::: I hope so!
|
|
assert(triangulator->GetFirstIndexNumber() == 0);
|
|
|
|
vvloop = pvorout->pointlist;
|
|
vvindex = 0;
|
|
vvcount = pvorout->numberofpoints;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::vvIterator Delaunay::vvend() {
|
|
vvIterator vvit;
|
|
vvit.vvloop = nullptr;
|
|
vvit.vvindex = 0;
|
|
vvit.vvcount = 0;
|
|
vvit.m_delaunay = nullptr;
|
|
|
|
return vvit;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::vvIterator Delaunay::vvIterator::operator++() {
|
|
vvIterator vit;
|
|
vit.vvloop = vvloop;
|
|
vit.vvindex = vvindex;
|
|
vit.m_delaunay = m_delaunay;
|
|
|
|
advance(1);
|
|
|
|
return vit;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::Point& Delaunay::vvIterator::operator*() const {
|
|
Point::NT* pointlist = (Point::NT*)vvloop;
|
|
|
|
// UB! -> but also in original code...OPEN TODO::: !!!
|
|
return *((Point*)(pointlist + vvindex));
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
void Delaunay::vvIterator::advance(int steps) {
|
|
int stepSize = 2;
|
|
assert(Point().dim() == stepSize);
|
|
|
|
if (vvindex/stepSize + steps < vvcount) {
|
|
vvindex += steps * stepSize;
|
|
}
|
|
else {
|
|
// at end
|
|
vvindex = 0;
|
|
vvloop = nullptr;
|
|
}
|
|
|
|
assert(vvindex / stepSize < vvcount);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool operator==(Delaunay::vvIterator const& lhs,
|
|
Delaunay::vvIterator const& rhs) {
|
|
if (lhs.vvloop == rhs.vvloop &&
|
|
lhs.vvindex == rhs.vvindex) return true;
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool operator!=(Delaunay::vvIterator const& lhs,
|
|
Delaunay::vvIterator const& rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
|
|
///////////////////////////////
|
|
//
|
|
// Voronoi Edge Iterator Impl.
|
|
// (added mrkkrj)
|
|
//
|
|
///////////////////////////////
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::veIterator::veIterator()
|
|
: m_delaunay(nullptr), veloop(nullptr), veindex(0), vecount(0) {
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::veIterator::veIterator(Delaunay* triangulator) {
|
|
m_delaunay = triangulator;
|
|
triangulateio* pvorout = (struct triangulateio*)triangulator->m_vorout;
|
|
|
|
// TEST::: I hope so!
|
|
assert(triangulator->GetFirstIndexNumber() == 0);
|
|
|
|
veloop = pvorout->edgelist;
|
|
veindex = 0;
|
|
vecount = pvorout->numberofedges;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::veIterator Delaunay::veend() {
|
|
veIterator veit;
|
|
veit.veloop = nullptr;
|
|
veit.veindex = 0;
|
|
veit.vecount = 0;
|
|
veit.m_delaunay = nullptr;
|
|
|
|
return veit;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::veIterator Delaunay::veIterator::operator++() {
|
|
veIterator veit;
|
|
veit.veloop = veloop;
|
|
veit.veindex = veindex;
|
|
veit.m_delaunay = m_delaunay;
|
|
|
|
// an edge is represented as 2 integer indexes!
|
|
if (veindex / 2 + 1 < vecount ) {
|
|
veindex += 2;
|
|
}
|
|
else {
|
|
veindex = 0;
|
|
veloop = nullptr;
|
|
}
|
|
|
|
assert(veindex / 2 < vecount);
|
|
return veit;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::veIterator::startPointId() const {
|
|
if (!veloop) {
|
|
assert(false);
|
|
return -1;
|
|
}
|
|
|
|
auto edgelist = (int*)veloop;
|
|
return edgelist[veindex];
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
int Delaunay::veIterator::endPointId(Point& normvec) const {
|
|
if (!veloop) {
|
|
assert(false);
|
|
return -1;
|
|
}
|
|
|
|
assert(veindex / 2 < vecount);
|
|
auto edgelist = (int*)veloop;
|
|
int idx = edgelist[veindex + 1];
|
|
|
|
if (idx == -1) {
|
|
triangulateio* pvorout = (struct triangulateio*)m_delaunay->m_vorout;
|
|
auto normlist = pvorout->normlist;
|
|
|
|
// normlist has same no. of elements as edgelist!
|
|
normvec[0] = normlist[veindex];
|
|
normvec[1] = normlist[veindex + 1];
|
|
|
|
assert(!(normvec[0] == 0.0 && normvec[1] == 0.0));
|
|
}
|
|
else {
|
|
normvec[0] = 0.0;
|
|
normvec[1] = 0.0;
|
|
}
|
|
|
|
return idx;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool operator==(Delaunay::veIterator const& lhs,
|
|
Delaunay::veIterator const& rhs) {
|
|
if (lhs.veloop == rhs.veloop &&
|
|
lhs.veindex == rhs.veindex) return true;
|
|
return false;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
bool operator!=(Delaunay::veIterator const& lhs,
|
|
Delaunay::veIterator const& rhs) {
|
|
return !(lhs == rhs);
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
const Delaunay::Point& Delaunay::Org(veIterator const& eit)
|
|
{
|
|
auto pointId = eit.startPointId();
|
|
|
|
vvIterator vit(this);
|
|
vit.advance(pointId);
|
|
return *vit;
|
|
}
|
|
|
|
/*!
|
|
*/
|
|
Delaunay::Point Delaunay::Dest(veIterator const& eit, bool& finiteEdge)
|
|
{
|
|
// OPEN TODO::: optimization --- use const& as return value!
|
|
|
|
Point normvec;
|
|
|
|
auto pointId = eit.endPointId(normvec);
|
|
finiteEdge = pointId != -1;
|
|
|
|
if (pointId == -1) {
|
|
assert(normvec.sqr_length() != 0.0);
|
|
return normvec;
|
|
} else {
|
|
assert(normvec.sqr_length() == 0.0);
|
|
|
|
vvIterator vit(this);
|
|
vit.advance(pointId);
|
|
return *vit;
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
///////////////////// FUNZIONI AGGIUNTE per scorrere vertici e triangoli ///////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
std::vector< Delaunay::Point> Delaunay::MyVertexTraverse( ) {
|
|
|
|
typedef Triwrap::vertex vertex;
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
Triwrap::__pbehavior * tpbehavior = (Triwrap::__pbehavior *) m_pbehavior;
|
|
Triwrap *pTriangleWrap = (Triwrap *) m_triangleWrap;
|
|
|
|
std::vector< Delaunay::Point> vVertex ;
|
|
|
|
pTriangleWrap->traversalinit(&( tpmesh->vertices)) ;
|
|
double * vertexloop = pTriangleWrap->vertextraverse(tpmesh) ;
|
|
|
|
while (vertexloop != (vertex) NULL) {
|
|
if ( ! tpbehavior->jettison || ( vertexloop)[tpmesh->vertexmarkindex] != UNDEADVERTEX )
|
|
vVertex.push_back( Delaunay::Point( vertexloop[0],vertexloop[1])) ;
|
|
vertexloop = pTriangleWrap->vertextraverse(tpmesh) ;
|
|
}
|
|
return vVertex ;
|
|
}
|
|
|
|
std::vector< int> Delaunay::MyTriangleTraverse() {
|
|
|
|
typedef Triwrap::vertex vertex ;
|
|
typedef Triwrap::triangle triangle ;
|
|
typedef Triwrap::__otriangle trianglelooptype; // oriented triangle
|
|
|
|
Triwrap::__pmesh * tpmesh = (Triwrap::__pmesh *) m_pmesh;
|
|
Triwrap::__pbehavior * tpbehavior = (Triwrap::__pbehavior *) m_pbehavior;
|
|
Triwrap *pTriangleWrap = (Triwrap *) m_triangleWrap;
|
|
|
|
std::vector< int> vTrg ;
|
|
vertex p1, p2, p3;
|
|
|
|
pTriangleWrap->traversalinit(&( tpmesh->triangles)) ;
|
|
|
|
trianglelooptype ptriangleloop ;
|
|
ptriangleloop.tri = pTriangleWrap->triangletraverse(tpmesh);
|
|
ptriangleloop.orient = 0;
|
|
|
|
while ( ptriangleloop.tri != (triangle *) NULL) {
|
|
|
|
org( ptriangleloop, p1);
|
|
dest( ptriangleloop, p2);
|
|
apex( ptriangleloop, p3);
|
|
|
|
int n1 = ((int*)p1)[tpmesh->vertexmarkindex] - tpbehavior->firstnumber ;
|
|
int n2 = ((int*)p2)[tpmesh->vertexmarkindex] - tpbehavior->firstnumber ;
|
|
int n3 = ((int*)p3)[tpmesh->vertexmarkindex] - tpbehavior->firstnumber ;
|
|
|
|
vTrg.emplace_back( n1) ;
|
|
vTrg.emplace_back( n2) ;
|
|
vTrg.emplace_back( n3) ;
|
|
|
|
ptriangleloop.tri = pTriangleWrap->triangletraverse(tpmesh) ;
|
|
}
|
|
|
|
return vTrg ;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace tpp ends.
|