bool Vectorize::vconncet() { connect(m_gui.fileButton, SIGNAL(clicked()), this, SLOT(open())); connect(m_gui.runButton, SIGNAL(clicked()), this, SLOT(run())); connect(m_gui.meshButton, SIGNAL(clicked()), this, SLOT(delaunay())); connect(m_gui.testButton, SIGNAL(clicked()), this, SLOT(test())); connect(m_gui.saveButton, SIGNAL(clicked()), this, SLOT(save())); return true; }
void ClusterHierarchyBuilder::CreateInitialEdges(const Vec2 *pts,int numPts) { FortunesAlgorithm delaunay(pts,numPts); mEdges = new Edge[delaunay.mTriangles.size() * 3]; Edge *freeEdge = mEdges; for(const FortunesAlgorithm::Triangle &tri : delaunay.mTriangles) { int prev = tri.mIndices[2]; for(int j = 0;j < 3;j++) { int cur = tri.mIndices[j]; int from = prev; int to = cur; if(from > to) std::swap(to,from); Edge *edge = freeEdge++; edge->mFrom = mNodes[from]; edge->mFromLLNext = mNodes[from]->mEdgeLLHead; mNodes[from]->mEdgeLLHead = edge; edge->mTo = mNodes[to]; edge->mToLLNext = mNodes[to]->mEdgeLLHead; mNodes[to]->mEdgeLLHead = edge; edge->mSqrLen = (mNodes[from]->mCentroid - mNodes[to]->mCentroid).GetSqrLen(); edge->mInHeap = false; prev = cur; } } for(Node *node : mNodes) { node->mEdgeLLHead = SortSinglyLinkedList(node->mEdgeLLHead,SortEdgesTraits(node)); node->mEdgeLLHead = RemoveDupsSinglyLinkedList(node->mEdgeLLHead, RemoveDupEdgesTraits(node)); for(Edge *edge = node->mEdgeLLHead;edge;edge = edge->LLGetNext(node)) { if(!edge->mInHeap) { edge->mInHeap = true; mEdgesHeap.Push(edge); } } } }
//----------------------------------------------------------------------- void Triangulator::triangulate(const Shape& shape, std::vector<int>& output) { // Do the Delaunay triangulation PointList pl = shape.getPoints(); DelaunayTriangleBuffer dtb; delaunay(pl, dtb); addConstraints(shape, dtb); //Outputs index buffer for (DelaunayTriangleBuffer::iterator it = dtb.begin(); it!=dtb.end();it++) { output.push_back(it->i[0]); output.push_back(it->i[1]); output.push_back(it->i[2]); } }
void EditorScene::addPoint(const cocos2d::Vec2 &rawpos) { clearSelection(); auto pos = help_touchPoint2editPosition(rawpos); auto point = std::make_shared<EEPoint>(); point->position = help_editPosition2relativePosition(pos); point->height = findNearestHeight(point->position); point->sprite = Sprite::create("images/point_normal.png"); point->sprite->setPosition(help_relativePosition2editPosition(point->position)); point->sprite->setZOrder(Z_POINTS); point->sprite->setScale(DOT_SCALE); _pointLayer->addChild(point->sprite); point->pid = nextPid(); _points[_frameIndex][point->pid] = point; delaunay(); refreshLines(); refreshTriangles(); }
void EditorScene::deletePoint(const cocos2d::Vec2 &rawpos) { clearSelection(); auto pos = help_touchPoint2editPosition(rawpos); for (auto & pair : _points[_frameIndex]) { auto distance = pair.second->sprite->getPosition().distance(pos); if (distance < pair.second->sprite->getContentSize().width * pair.second->sprite->getScale() /2){ CCLOG("delete point"); _pointLayer->removeChild(pair.second->sprite); _points[_frameIndex].erase(pair.first); _selectedPoints.remove(pair.second); delaunay(); refreshLines(); refreshTriangles(); return; } } }
void Tetgen::delaunay(Crowd* crowd) { setCurrentCrowd(crowd); delaunay(); }
// Customized triangulation call. void custom_triangulate(char *triswitches, struct triangulateio *in, struct triangulateio *out, struct triangulateio *vorout, const int *outside, const int *inside) { struct mesh m; struct behavior b; //REAL *holearray; //REAL *regionarray; triangleinit(& m); parsecommandline(1, & triswitches, & b); //b.verbose=2; m.steinerleft = b.steiner; transfernodes(& m, & b, in->pointlist, in->pointattributelist, in->pointmarkerlist, in->numberofpoints, in->numberofpointattributes); if ( b.refine ) { m.hullsize = reconstruct(& m, & b, in->trianglelist, in->triangleattributelist, in->trianglearealist, in->numberoftriangles, in->numberofcorners, in->numberoftriangleattributes, in->segmentlist, in->segmentmarkerlist, in->numberofsegments); } else { m.hullsize = delaunay(& m, & b); } m.infvertex1 = ( vertex ) NULL; m.infvertex2 = ( vertex ) NULL; m.infvertex3 = ( vertex ) NULL; if ( b.usesegments ) { m.checksegments = 1; if ( !b.refine ) { formskeleton(& m, & b, in->segmentlist, in->segmentmarkerlist, in->numberofsegments); } } #if 0 struct osub subsegloop; traversalinit(& m.subsegs); subsegloop.ss = subsegtraverse(& m); subsegloop.ssorient = 0; while ( subsegloop.ss != ( subseg * ) NULL ) { if ( subsegloop.ss != m.dummysub ) { REAL *p1, *p2; sorg(subsegloop, p1); sdest(subsegloop, p2); printf(" Connected (%f,%f) to (%f,%f)\n", p1 [ 0 ], p1 [ 1 ], p2 [ 0 ], p2 [ 1 ]); subsegloop.ss = subsegtraverse(& m); } } #endif if ( b.poly && ( m.triangles.items > 0 ) ) { //holearray = in->holelist; m.holes = in->numberofholes; //regionarray = in->regionlist; m.regions = in->numberofregions; if ( !b.refine ) { /* Only increase quality if the regions are properly defined. */ int sane = custom_carveholes(& m, & b, outside, inside); b.quality *= sane; if ( sane == 0 ) { printf("Probably bad PSLG\n"); exit(-1); } } } else { m.holes = 0; m.regions = 0; } if ( b.quality && ( m.triangles.items > 0 ) ) { enforcequality(& m, & b); } m.edges = ( 3l * m.triangles.items + m.hullsize ) / 2l; if ( b.order > 1 ) { highorder(& m, & b); } if ( !b.quiet ) { printf("\n"); } if ( b.jettison ) { out->numberofpoints = m.vertices.items - m.undeads; } else { out->numberofpoints = m.vertices.items; } out->numberofpointattributes = m.nextras; out->numberoftriangles = m.triangles.items; out->numberofcorners = ( b.order + 1 ) * ( b.order + 2 ) / 2; out->numberoftriangleattributes = m.eextras; out->numberofedges = m.edges; if ( b.usesegments ) { out->numberofsegments = m.subsegs.items; } else { out->numberofsegments = m.hullsize; } if ( vorout != ( struct triangulateio * ) NULL ) { vorout->numberofpoints = m.triangles.items; vorout->numberofpointattributes = m.nextras; vorout->numberofedges = m.edges; } if ( b.nonodewritten || ( b.noiterationnum && m.readnodefile ) ) { if ( !b.quiet ) { printf("NOT writing vertices.\n"); } numbernodes(& m, & b); } else { writenodes(& m, & b, & out->pointlist, & out->pointattributelist, & out->pointmarkerlist); } // Simp. always write the triangles. writeelements(& m, & b, & out->trianglelist, & out->triangleattributelist); if ( b.poly || b.convex ) { writepoly(& m, & b, & out->segmentlist, & out->segmentmarkerlist); out->numberofholes = m.holes; out->numberofregions = m.regions; if ( b.poly ) { out->holelist = in->holelist; out->regionlist = in->regionlist; } else { out->holelist = ( REAL * ) NULL; out->regionlist = ( REAL * ) NULL; } } if ( b.edgesout ) { writeedges(& m, & b, & out->edgelist, & out->edgemarkerlist); } // Simp. no voronoi if ( b.neighbors ) { writeneighbors(& m, & b, & out->neighborlist); } // Simp. No statistics. if ( b.docheck ) { checkmesh(& m, & b); checkdelaunay(& m, & b); } triangledeinit(& m, & b); }
static int DelaunayClustering(int MaxClusterSize) { int Count = 0, Count1, Count2 = 0, i, j = 0; Edge *EdgeSet, Key; Node *From, *To, *N, *F, *T; point *u, *v; edge *e_start, *e; delaunay(Dimension); for (i = 0; i < Dimension; i++) { u = &p_array[i]; e_start = e = u->entry_pt; do { v = Other_point(e, u); if (u->id < v->id) Count++; } while ((e = Next(e, u)) != e_start); } assert(EdgeSet = (Edge *) malloc(Count * sizeof(Edge))); for (i = 0; i < Dimension; i++) { u = &p_array[i]; e_start = e = u->entry_pt; do { v = Other_point(e, u); if (u->id < v->id) { EdgeSet[j].From = From = &NodeSet[u->id]; EdgeSet[j].To = To = &NodeSet[v->id]; EdgeSet[j++].Cost = FixedOrCommon(From, To) ? INT_MIN : Distance(From, To) * Precision + From->Pi + To->Pi; } } while ((e = Next(e, u)) != e_start); } free_memory(); if (WeightType == GEO || WeightType == GEOM || WeightType == GEO_MEEUS || WeightType == GEOM_MEEUS) { N = FirstNode; while ((N = N->Suc) != FirstNode) if ((N->Y > 0) != (FirstNode->Y > 0)) break; if (N != FirstNode) { N = FirstNode; do N->Zc = N->Y; while ((N = N->Suc) != FirstNode); /* Transform longitude (180 and -180 map to 0) */ From = FirstNode; do { From->Zc = From->Y; if (WeightType == GEO || WeightType == GEO_MEEUS) From->Y = (int) From->Y + 5.0 * (From->Y - (int) From->Y) / 3.0; From->Y += From->Y > 0 ? -180 : 180; if (WeightType == GEO || WeightType == GEO_MEEUS) From->Y = (int) From->Y + 3.0 * (From->Y - (int) From->Y) / 5.0; } while ((From = From->Suc) != FirstNode); delaunay(Dimension); do From->Y = From->Zc; while ((From = From->Suc) != FirstNode); qsort(EdgeSet, Count, sizeof(Edge), compareFromTo); for (i = 0; i < Dimension; i++) { u = &p_array[i]; e_start = e = u->entry_pt; do { v = Other_point(e, u); if (u->id < v->id) Count2++; } while ((e = Next(e, u)) != e_start); } Count1 = Count; assert(EdgeSet = (Edge *) realloc(EdgeSet, (Count1 + Count2) * sizeof(Edge))); for (i = 0; i < Dimension; i++) { u = &p_array[i]; e_start = e = u->entry_pt; do { v = Other_point(e, u); if (u->id > v->id) continue; Key.From = From = &NodeSet[u->id]; Key.To = To = &NodeSet[v->id]; if (!bsearch (&Key, EdgeSet, Count1, sizeof(Edge), compareFromTo)) { EdgeSet[Count].From = From; EdgeSet[Count].To = To; EdgeSet[Count].Cost = FixedOrCommon(From, To) ? INT_MIN : Distance(From, To) * Precision + From->Pi + To->Pi; Count++; } } while ((e = Next(e, u)) != e_start); } free_memory(); } } qsort(EdgeSet, Count, sizeof(Edge), compareCost); /* Union-Find with path compression */ N = FirstNode; do { N->Next = N; N->Size = 1; } while ((N = N->Suc) != FirstNode); for (i = 0; i < Count; i++) { for (F = EdgeSet[i].From; F != F->Next;) F = F->Next = F->Next->Next; for (T = EdgeSet[i].To; T != T->Next;) T = T->Next = T->Next->Next; if (F != T && F->Size + T->Size <= MaxClusterSize) { if (F->Size < T->Size) { F->Next = T; T->Size += F->Size; } else { T->Next = F; F->Size += T->Size; } } } free(EdgeSet); Count = 0; N = FirstNode; do { if (N->Next == N && N->Size > 3) N->Subproblem = ++Count; } while ((N = N->Suc) != FirstNode); do { for (T = N; T != T->Next;) T = T->Next = T->Next->Next; N->Subproblem = T->Subproblem; } while ((N = N->Suc) != FirstNode); return Count; }
void CreateDelaunayCandidateSet() { Node *From, *To; point *u, *v; edge *e_start, *e; int d, i, Count; if (TraceLevel >= 2) printff("Creating Delaunay candidate set ... "); if (Level == 0 && MaxCandidates == 0) { AddTourCandidates(); From = FirstNode; do { if (!From->CandidateSet) eprintf("MAX_CANDIDATES = 0: No candidates"); } while ((From = From->Suc) != FirstNode); if (TraceLevel >= 2) printff("done\n"); return; } /* Find the Delaunay edges */ delaunay(Dimension); /* Add the Delaunay edges to the candidate set */ for (i = 0; i < Dimension; i++) { u = &p_array[i]; From = &NodeSet[u->id]; e_start = e = u->entry_pt; Count = 0; do { v = Other_point(e, u); if (u < v) { To = &NodeSet[v->id]; d = D(From, To); AddCandidate(From, To, d, 1); AddCandidate(To, From, d, 1); } } while ((e = Next(e, u)) != e_start && ++Count < Dimension); } free_memory(); if (Level == 0 && (WeightType == GEO || WeightType == GEOM || WeightType == GEO_MEEUS || WeightType == GEOM_MEEUS)) { if (TraceLevel >= 2) printff("done\n"); From = FirstNode; while ((From = From->Suc) != FirstNode) if ((From->Y > 0) != (FirstNode->Y > 0)) break; if (From != FirstNode) { /* Transform longitude (180 and -180 map to 0) */ From = FirstNode; do { From->Zc = From->Y; if (WeightType == GEO || WeightType == GEO_MEEUS) From->Y = (int) From->Y + 5.0 * (From->Y - (int) From->Y) / 3.0; From->Y += From->Y > 0 ? -180 : 180; if (WeightType == GEO || WeightType == GEO_MEEUS) From->Y = (int) From->Y + 3.0 * (From->Y - (int) From->Y) / 5.0; } while ((From = From->Suc) != FirstNode); Level++; CreateDelaunayCandidateSet(); Level--; From = FirstNode; do From->Y = From->Zc; while ((From = From->Suc) != FirstNode); } } if (Level == 0) { AddTourCandidates(); /* Add quadrant neighbors if any node has less than two candidates. That is, if it should happen that delaunay_edges fails. */ From = FirstNode; do { if (From->CandidateSet == 0 || From->CandidateSet[0].To == 0 || From->CandidateSet[1].To == 0) { if (TraceLevel >= 2) printff("*** Not complete ***\n"); AddExtraCandidates(CoordType == THREED_COORDS ? 8 : 4, QUADRANT, 1); break; } } while ((From = From->Suc) != FirstNode); if (TraceLevel >= 2) printff("done\n"); } }
/*Type of Cut Strategy is defined as: * (useAltCut, useVertical) = (true, true) => Alternating Cuts * (useAltCut, useVertical) = (true, false) => Horizontal Cuts* * (useAltCut, useVertical) = (false, true) => Vertical Cuts * */ void delaunay(Vertex **ppVertices, long numVertices, Edge **ppLe, Edge **ppRe, bool useAltCuts, bool useVertical) { NOT_NULL(ppVertices); if(numVertices == 2) { Edge *pA = Edge::makeEdge(); if(*ppVertices[0] > *ppVertices[1]) { ELEM_SWAP(ppVertices[0], ppVertices[1]); } pA->setOrg(ppVertices[0]); pA->setDest(ppVertices[1]); *ppLe = pA; *ppRe = pA->Sym(); } else if(numVertices == 3) { Edge *pA = Edge::makeEdge(), *pB = Edge::makeEdge(), *pC = 0; if(*ppVertices[0] > *ppVertices[1]) { ELEM_SWAP(ppVertices[0], ppVertices[1]); } if(*ppVertices[1] > *ppVertices[2]) { ELEM_SWAP(ppVertices[1], ppVertices[2]); } Edge::splice(pA->Sym(), pB); pA->setOrg(ppVertices[0]); pA->setDest(ppVertices[1]); pB->setOrg(ppVertices[1]); pB->setDest(ppVertices[2]); REAL ccw = orient2d(ppVertices[0]->Pos(), ppVertices[1]->Pos(), ppVertices[2]->Pos()); if(ccw > 0) { pC = Edge::connect(pB, pA); *ppLe = pA; *ppRe = pB->Sym(); } else if(ccw < 0) { pC = Edge::connect(pB, pA); *ppLe = pC->Sym(); *ppRe = pC; } else { *ppLe = pA; *ppRe = pB->Sym(); } } else { long middle = std::floor(numVertices/2); Edge *pLdo = 0, *pLdi = 0, *pRdi = 0, *pRdo = 0; //These vertices are used for merging a horizontal cut Vertex *pBotMax = 0, //highest vertex of bottom half *pTopMin = 0, //lowest vertex of top half *pMin = 0, //Lexicographically max vertex *pMax = 0; //Lexicographically min vertex //Find median partition by X or Y, depending on whether we're using a vertical cut std::nth_element(ppVertices, ppVertices+middle, ppVertices+numVertices, useVertical ? Vertex::lessX : Vertex::lessY); //Recursive calls delaunay(ppVertices, middle, &pLdo, &pLdi, useAltCuts, useAltCuts ? !useVertical : useVertical); delaunay(ppVertices+middle, numVertices - middle, &pRdi, &pRdo, useAltCuts, useAltCuts ? !useVertical : useVertical); //Modify ldi be highest in bottom half and rdi to be lowest in top half if(!useVertical) { pBotMax = ppVertices[0]; pTopMin = ppVertices[middle]; pMin = (*ppVertices[0] < *ppVertices[middle]) ? ppVertices[0] : ppVertices[middle]; pMax = (*ppVertices[0] > *ppVertices[middle]) ? ppVertices[0] : ppVertices[middle];; for(long i=1; i < middle; i++) { if(*ppVertices[i] < *pMin) { pMin = ppVertices[i]; } else if(*ppVertices[i] > *pMax) { pMax = ppVertices[i]; } if(ppVertices[i]->gtY(*pBotMax)) { pBotMax = ppVertices[i]; } } for(long i=middle+1; i < numVertices; i++) { if(*ppVertices[i] < *pMin) { pMin = ppVertices[i]; } else if(*ppVertices[i] > *pMax) { pMax = ppVertices[i]; } if(ppVertices[i]->ltY(*pTopMin)) { pTopMin = ppVertices[i]; } } pLdi = pBotMax->getCWHullEdge(); pRdi = pTopMin->getCCWHullEdge(); } //Compute the lower common tangent of two sets of vertices while (1) { if(pLdi->leftOf(pRdi->Org())) { pLdi = pLdi->Lnext(); } else if(pRdi->rightOf(pLdi->Org())) { pRdi = pRdi->Rprev(); } else { break; } } // Create a first cross edge pBasel from pRdi.origin to pLdi.origin Edge *pBasel = Edge::connect(pRdi->Sym(), pLdi); if(pLdi->Org() == pLdo->Org()) { pLdo = pBasel->Sym(); } if(pRdi->Org() == pRdo->Org()) { pRdo = pBasel; } //Merging two halves while(1) { //Locate the first Left point pLcand to be encou Edge *pLcand = pBasel->Sym()->Onext(); bool leftFinished = !pLcand->valid(pBasel); if(!leftFinished) { while(incircle(pBasel->Dest()->Pos(), pBasel->Org()->Pos(), pLcand->Dest()->Pos(), pLcand->Onext()->Dest()->Pos()) > 0) { Edge *pT = pLcand->Onext(); Edge::deleteEdge(pLcand); pLcand = pT; } } //Symmetrically locate the first R point to be hit Edge *pRcand = pBasel->Oprev(); bool rightFinished = !pRcand->valid(pBasel); if(!rightFinished) { while(incircle(pBasel->Dest()->Pos(), pBasel->Org()->Pos(), pRcand->Dest()->Pos(), pRcand->Oprev()->Dest()->Pos()) > 0) { Edge *pT = pRcand->Oprev(); Edge::deleteEdge(pRcand); pRcand = pT; } } //both are invalid, pBasel is upper common tangent if(leftFinished && rightFinished) { break; } //the next cross edge is to be connected to either pLcand.dest or pRcand.dest if(leftFinished || (!rightFinished && incircle(pLcand->Dest()->Pos(), pLcand->Org()->Pos(), pRcand->Org()->Pos(), pRcand->Dest()->Pos()) > 0)) { pBasel = Edge::connect(pRcand, pBasel->Sym()); } else { pBasel = Edge::connect(pBasel->Sym(), pLcand->Sym()); } } //Modify pLdo and pRdo if we merging a horizontal cut if(!useVertical) { pLdo = pMin->getCCWHullEdge(); pRdo = pMax->getCWHullEdge(); } *ppLe = pLdo; *ppRe = pRdo; } return; }
static bool buildPolyDetail(const float* in, const int nin, unsigned short reg, const float sampleDist, const float sampleMaxError, const rcCompactHeightfield& chf, const rcHeightPatch& hp, float* verts, int& nverts, rcIntArray& tris, rcIntArray& edges, rcIntArray& idx, rcIntArray& samples) { static const int MAX_VERTS = 256; static const int MAX_EDGE = 64; float edge[(MAX_EDGE+1)*3]; nverts = 0; for (int i = 0; i < nin; ++i) vcopy(&verts[i*3], &in[i*3]); nverts = nin; const float ics = 1.0f/chf.cs; // Tesselate outlines. // This is done in separate pass in order to ensure // seamless height values across the ply boundaries. if (sampleDist > 0) { for (int i = 0, j = nin-1; i < nin; j=i++) { const float* vj = &in[j*3]; const float* vi = &in[i*3]; // Make sure the segments are always handled in same order // using lexological sort or else there will be seams. if (fabsf(vj[0]-vi[0]) < 1e-6f) { if (vj[2] > vi[2]) rcSwap(vj,vi); } else { if (vj[0] > vi[0]) rcSwap(vj,vi); } // Create samples along the edge. float dx = vi[0] - vj[0]; float dy = vi[1] - vj[1]; float dz = vi[2] - vj[2]; float d = sqrtf(dx*dx + dz*dz); int nn = 1 + (int)floorf(d/sampleDist); if (nn > MAX_EDGE) nn = MAX_EDGE; if (nverts+nn >= MAX_VERTS) nn = MAX_VERTS-1-nverts; for (int k = 0; k <= nn; ++k) { float u = (float)k/(float)nn; float* pos = &edge[k*3]; pos[0] = vj[0] + dx*u; pos[1] = vj[1] + dy*u; pos[2] = vj[2] + dz*u; pos[1] = chf.bmin[1] + getHeight(pos, chf.bmin, ics, hp)*chf.ch; } // Simplify samples. int idx[MAX_EDGE] = {0,nn}; int nidx = 2; for (int k = 0; k < nidx-1; ) { const int a = idx[k]; const int b = idx[k+1]; const float* va = &edge[a*3]; const float* vb = &edge[b*3]; // Find maximum deviation along the segment. float maxd = 0; int maxi = -1; for (int m = a+1; m < b; ++m) { float d = distancePtSeg(&edge[m*3],va,vb); if (d > maxd) { maxd = d; maxi = m; } } // If the max deviation is larger than accepted error, // add new point, else continue to next segment. if (maxi != -1 && maxd > rcSqr(sampleMaxError)) { for (int m = nidx; m > k; --m) idx[m] = idx[m-1]; idx[k+1] = maxi; nidx++; } else { ++k; } } // Add new vertices. for (int k = 1; k < nidx-1; ++k) { vcopy(&verts[nverts*3], &edge[idx[k]*3]); nverts++; } } } // Tesselate the base mesh. edges.resize(0); tris.resize(0); idx.resize(0); delaunay(nverts, verts, idx, tris, edges); if (sampleDist > 0) { // Create sample locations in a grid. float bmin[3], bmax[3]; vcopy(bmin, in); vcopy(bmax, in); for (int i = 1; i < nin; ++i) { vmin(bmin, &in[i*3]); vmax(bmax, &in[i*3]); } int x0 = (int)floorf(bmin[0]/sampleDist); int x1 = (int)ceilf(bmax[0]/sampleDist); int z0 = (int)floorf(bmin[2]/sampleDist); int z1 = (int)ceilf(bmax[2]/sampleDist); samples.resize(0); for (int z = z0; z < z1; ++z) { for (int x = x0; x < x1; ++x) { float pt[3]; pt[0] = x*sampleDist; pt[2] = z*sampleDist; // Make sure the samples are not too close to the edges. if (distToPoly(nin,in,pt) > -sampleDist/2) continue; samples.push(x); samples.push(getHeight(pt, chf.bmin, ics, hp)); samples.push(z); } } // Add the samples starting from the one that has the most // error. The procedure stops when all samples are added // or when the max error is within treshold. const int nsamples = samples.size()/3; for (int iter = 0; iter < nsamples; ++iter) { // Find sample with most error. float bestpt[3]; float bestd = 0; for (int i = 0; i < nsamples; ++i) { float pt[3]; pt[0] = samples[i*3+0]*sampleDist; pt[1] = chf.bmin[1] + samples[i*3+1]*chf.ch; pt[2] = samples[i*3+2]*sampleDist; float d = distToTriMesh(pt, verts, nverts, &tris[0], tris.size()/4); if (d < 0) continue; // did not hit the mesh. if (d > bestd) { bestd = d; vcopy(bestpt,pt); } } // If the max error is within accepted threshold, stop tesselating. if (bestd <= sampleMaxError) break; // Add the new sample point. vcopy(&verts[nverts*3],bestpt); nverts++; // Create new triangulation. // TODO: Incremental add instead of full rebuild. edges.resize(0); tris.resize(0); idx.resize(0); delaunay(nverts, verts, idx, tris, edges); if (nverts >= MAX_VERTS) break; } } return true; }
std::vector<Triangle> Triangle::triangulate( const std::vector<ci::Vec2f> & points, const std::vector<ci::Vec2f> & contour) { // Initialize output list vector<Triangle> triangles; // Convert Cinder points to Delaunay points int size = points.size(); Delaunay::Point position; vector<Delaunay::Point> positions; for ( float i = 0.0f; i < size; i++ ) { Vec2f point = points[i]; position[ 0 ] = point.x; position[ 1 ] = point.y; positions.push_back( position ); } // Triangulate points Delaunay delaunay( positions ); delaunay.Triangulate(); // Triangle IDs int32_t id = 0; int N = contour.size(); // Iterate through triangles for ( Delaunay::fIterator triIt = delaunay.fbegin(); triIt != delaunay.fend(); ++triIt ) { // Get point indexes int a = delaunay.Org( triIt ); int b = delaunay.Dest( triIt ); int c = delaunay.Apex( triIt ); // Set positions in triangles Vec2f triangle[ 3 ]; triangle[ 0 ] = points[ a ]; triangle[ 1 ] = points[ b ]; triangle[ 2 ] = points[ c ]; // Find center of triangle Vec2f p = Vec2f( ( triangle[ 0 ].x + triangle[ 1 ].x + triangle[ 2 ].x ) / 3.0f, ( triangle[ 0 ].y + triangle[ 1 ].y + triangle[ 2 ].y ) / 3.0f ); // Initialize properties to test triangle position Vec2f p1 = contour[ 0 ]; // Iterate through points int32_t counter = 0; for (int i=1;i<=N;i++){ const Vec2f& p2 = contour[i % N]; // Compare centroid of this triangle to the previous one if ( p.y > math<float>::min( p1.y, p2.y ) && p.y <= math<float>::max( p1.y, p2.y ) && p.x <= math<float>::max( p1.x, p2.x ) && p1.y != p2.y && ( p1.x == p2.x || p.x <= ( p.y - p1.y ) * ( p2.x - p1.x ) / ( p2.y - p1.y ) + p1.x ) ) { counter++; } // Assign this point to last p1 = p2; } // Only include triangles which are inside shape if ( counter % 2 != 0 ) { // Add triangle to list Triangle triData( triangle[ 0 ], triangle[ 1 ], triangle[ 2 ], id, (float)delaunay.area( triIt ), p ); triData.mIndex[0] = a; triData.mIndex[1] = b; triData.mIndex[2] = c; triangles.push_back( triData ); // Increase default ID id++; } } // Return triangles return triangles; }
/* Based on Lloyds Algorithm (Lloyd, S. IEEE, 1982) */ void smooth(configInfo *par, struct grid *gp){ double mindist; /* Distance to closest neighbor */ int k=0,j,i; /* counters */ int sg; /* counter for smoothing the grid */ int cn; double move[3]; /* Auxillary array for smoothing the grid */ double dist; /* Distance to a neighbor */ struct cell *dc=NULL; /* Not used at present. */ unsigned long numCells; for(sg=0;sg<N_SMOOTH_ITERS;sg++){ delaunay(DIM, gp, (unsigned long)par->ncell, 0, 0, &dc, &numCells); distCalc(par, gp); for(i=0;i<par->pIntensity;i++){ mindist=1e30; cn=-1; for(k=0;k<gp[i].numNeigh;k++){ if(gp[i].neigh[k]->sink==0){ if(gp[i].ds[k]<mindist){ mindist=gp[i].ds[k]; cn=k; } } } if(par->radius-sqrt(gp[i].x[0]*gp[i].x[0] + gp[i].x[1]*gp[i].x[1] + gp[i].x[2]*gp[i].x[2])<mindist) cn=-1; if(cn>-1) { for(k=0;k<DIM;k++){ move[k] = gp[i].x[k] - gp[i].dir[cn].x[k]*0.20; } if((move[0]*move[0]+move[1]*move[1]+move[2]*move[2])<par->radiusSqu && (move[0]*move[0]+move[1]*move[1]+move[2]*move[2])>par->minScaleSqu){ for(k=0;k<DIM;k++) gp[i].x[k]=move[k]; } } } for(i=par->pIntensity;i<par->ncell;i++){ mindist=1e30; cn=-1; for(k=0;k<gp[i].numNeigh;k++){ if(gp[i].neigh[k]->sink==1){ if(gp[i].ds[k]<mindist){ mindist=gp[i].ds[k]; cn=k; } } } j=gp[i].neigh[cn]->id; for(k=0;k<DIM;k++){ gp[i].x[k] = gp[i].x[k] - (gp[j].x[k]-gp[i].x[k]) * 0.15; } dist=par->radius/sqrt(gp[i].x[0]*gp[i].x[0] + gp[i].x[1]*gp[i].x[1] + gp[i].x[2]*gp[i].x[2]); for(k=0;k<DIM;k++){ gp[i].x[k] *= dist; } } if(!silent) progressbar((double)(sg+1)/(double)N_SMOOTH_ITERS, 5); free(dc); } }
void TIN::create(const mydefs::Points3d& thePoints3d) { // Set input values for triangulation TTriangulationIO in; // Number of points in.numberofpoints = thePoints3d.size(); // One attribute for Z coordinate in.numberofpointattributes = 1; // Allocate memory for array of X and Y coordinates in.pointlist = (double *) malloc(in.numberofpoints * 2 * sizeof(double)); // Allocate memory for array of Z coordinates in.pointattributelist = (double *) malloc(in.numberofpoints * in.numberofpointattributes * sizeof(double)); in.pointmarkerlist = (int *) malloc(in.numberofpoints * sizeof(int)); // Zero segments, holes and regions in.numberofsegments = 0; in.numberofholes = 0; in.numberofregions = 0; // Populate arrays of coordinates int i = 0; for(mydefs::Points3d::const_iterator iter = thePoints3d.begin(); iter != thePoints3d.end(); ++iter) { in.pointlist[2*i] = (*iter)[0]; in.pointlist[2*i+1] = (*iter)[1]; in.pointattributelist[i] = (*iter)[2]; if(mMinZ > (*iter)[2]) { mMinZ = (*iter)[2]; } if(mMaxZ < (*iter)[2]) { mMaxZ = (*iter)[2]; } ++i; } // Prepare for triangulation transfernodes(mMesh, mBehavior, in.pointlist, in.pointattributelist, in.pointmarkerlist, in.numberofpoints, in.numberofpointattributes); // Triangulate points mMesh->hullsize = delaunay(mMesh, mBehavior); // Necessary maintenance mMesh->infvertex1 = (TVertex) NULL; mMesh->infvertex2 = (TVertex) NULL; mMesh->infvertex3 = (TVertex) NULL; mMesh->edges = (3l * mMesh->triangles.items + mMesh->hullsize) / 2l; // Set most recent triangle traversalinit(&mMesh->triangles); mRecentTri->tri = triangletraverse(mMesh); mRecentTri->orient = 0; // Free memory free(in.pointmarkerlist); free(in.pointattributelist); free(in.pointlist); }
int main(int argc, char **argv) { /* We choose to handle simple command line input */ int num_threads(0), box_length(0); try { if (argc == 5) { if (strcmp(argv[1], "-np") == 0 && strcmp(argv[3], "-bl") == 0) { sscanf(argv[2], "%d", &num_threads); sscanf(argv[4], "%d", &box_length); } else throw std::runtime_error("Incorrect arugments"); } else throw std::runtime_error("Incorrect number of arguments"); } catch(std::runtime_error &error) { std::cout << error.what() << std::endl; std::cout << "Use the form :: ./regulus -np X -bl Y \n"; return -1; } /* ... And we then build a point set to triangulate... */ unsigned long int num_points = std::pow(box_length, 3); std::vector<mesh> meshes; { std::vector<point> tmp_point_buff; tmp_point_buff.reserve(num_points); write_sorted_set(tmp_point_buff, num_points, box_length); auto m = num_points % num_threads; auto ppp = (num_points - m) / num_threads; for (int i = 0; i < num_threads; ++i) { unsigned long int num_per_tetra = 0; if (i != num_threads - 1) num_per_tetra = ppp; else num_per_tetra = ppp + m; meshes.emplace_back(num_per_tetra); /* Allocate root points */ auto tl = 3 * (box_length - 1); meshes[i].p_buffer.emplace_back(0, 0, 0); meshes[i].p_buffer.emplace_back(tl, 0, 0); meshes[i].p_buffer.emplace_back(0, tl, 0); meshes[i].p_buffer.emplace_back(0, 0, tl); meshes[i].p_position += 4; /* Allocate root tetrahedron */ new(meshes[i].t_position) tetra(&meshes[i].p_buffer[0], &meshes[i].p_buffer[1], &meshes[i].p_buffer[2], &meshes[i].p_buffer[3]); meshes[i].m_position = meshes[i].t_position; ++meshes[i].t_position; /* Copy partitioned points */ for (unsigned long int j = 0; j < num_per_tetra; ++j) { auto &cpy = tmp_point_buff[i*ppp + j]; meshes[i].p_buffer.emplace_back(cpy.x, cpy.y, cpy.z); } if (verbose >= 3) { std::cout << "\nthread : " << i << std::endl; for (auto it = meshes[i].p_buffer.begin(); it < meshes[i].p_buffer.end(); ++it) std::cout << *it << std::endl; } std::cout << std::endl; } } /* This is the crux of regulus We begin the triangulation */ double start_time = get_wall_time(); std::vector<std::thread> threads; for (int i = 0; i < num_threads; ++i) { threads.emplace_back([&meshes, i](void)->void { std::vector<std::pair<tetra*, unsigned int>> leaves; leaves.reserve(512); std::vector<tetra*> pile; pile.reserve(2048); point *p = meshes[i].p_buffer.data(); for (unsigned long int j = 5; j < meshes[i].p_buffer.size(); ++j) { if (verbose >= 1) std::cout << "\niterative index : " << j - 4 << std::endl; walk(leaves, p + j, meshes[i].m_position, &*(meshes[i].t_buffer.begin())); fracture(meshes[i], leaves, pile, p + j); delaunay(meshes[i], pile); leaves.clear(); pile.clear(); } }); } for (auto &t : threads) t.join(); unsigned long int tot_num_tetra = 0; for (auto &m : meshes) tot_num_tetra += m.num_tetra; double end_time = get_wall_time(); std::cout << "\nTotal number of tetrahedra triangulated : " << tot_num_tetra << std::endl; std::cout<< "\nTriangulated " << num_points << " points in " << end_time - start_time << " seconds" << std::endl; std::cout << num_points / ((end_time - start_time) * num_threads) << " points per second per thread" << std::endl; return 0; }