397
506
BoundCube boundC;
398
507
boundC.setBounds(v.getMinBounds(),v.getMaxBounds());
510
vector<TriangleWithIndexedVertices> indexedTriVec;
401
512
//Loop over the vertexs, with the mesh such that the
402
513
//nominally cube centres are now on a grid that is dual
403
514
//to the original grid (excluding the external boundary of course)
515
#pragma omp parallel for
404
516
for(size_t iX = 0; iX < nx-1; iX++)
405
for(size_t iY = 0; iY < ny-1; iY++)
406
for(size_t iZ = 0; iZ < nz-1; iZ++)
408
int iEdgeFlags,iFlagIndex;
409
iEdgeFlags=iFlagIndex=0;
411
//Lower left corner of cell for dual grid
412
position=v.getPoint(iX,iY,iZ) + gridSpacing*0.5;
414
//This must match a2fVertexOffset
415
vertexVal[0] = v.getData(iX,iY,iZ);
416
vertexVal[1] = v.getData(iX+1,iY,iZ);
417
vertexVal[2] = v.getData(iX+1,iY+1,iZ);
418
vertexVal[3] = v.getData(iX,iY+1,iZ);
420
vertexVal[4] = v.getData(iX,iY,iZ+1);
421
vertexVal[5] = v.getData(iX+1,iY,iZ+1);
422
vertexVal[6] = v.getData(iX+1,iY+1,iZ+1);
423
vertexVal[7] = v.getData(iX,iY+1,iZ+1);
425
//Find which vertices are inside of the surface and which are outside
426
for(int iVertexTest = 0; iVertexTest < 8; iVertexTest++)
428
if(vertexVal[iVertexTest] <= isoValue)
429
iFlagIndex |= 1<<iVertexTest;
431
//Find which edges are intersected by the surface
432
iEdgeFlags = aiCubeEdgeFlags[iFlagIndex];
518
int iEdgeFlags,iFlagIndex;
519
for(size_t iY = 0; iY < ny-1; iY++)
521
for(size_t iZ = 0; iZ < nz-1; iZ++)
523
iEdgeFlags=iFlagIndex=0;
525
//Lower left corner of cell for dual grid
526
position=v.getPoint(iX,iY,iZ) + gridSpacing*0.5;
528
//Find which vertices are inside of the surface and which are outside
529
for(int iVertexTest = 0; iVertexTest < 8; iVertexTest++)
532
f=v.getData(iX+VERTEX_OFFSET[iVertexTest][0],
533
iY+VERTEX_OFFSET[iVertexTest][1],
534
iZ+VERTEX_OFFSET[iVertexTest][2]);
536
//Compute posiion in triangle and edge connection
539
iFlagIndex |= 1<<iVertexTest;
541
//Find which edges are intersected by the surface
542
iEdgeFlags = aiCubeEdgeFlags[iFlagIndex];
547
//Find the point of intersection of the surface with each edge
548
//Then find the normal to the surface at those points
549
size_t asEdgeVertex[12];
550
for(int iEdge = 0; iEdge < 12; iEdge++)
552
//if there is an intersection on this edge
553
if(iEdgeFlags & (1<<iEdge))
555
//Store a reference to the vertex position
556
asEdgeVertex[iEdge] = v.getEdgeIndex(iX,iY,iZ,edgeRemap[iEdge]);
561
//Store the triangles that were found. There can be up to five per cube;
562
//these are listed as triplets in the connection table
563
for(int iTriangle = 0; iTriangle < 5; iTriangle++)
565
//Check to see if this triplet is a valid triangle
566
if(a2iTriangleConnectionTable[iFlagIndex][3*iTriangle] < 0)
569
TriangleWithIndexedVertices t;
570
for(int iCorner = 0; iCorner < 3; iCorner++)
573
iVertex = a2iTriangleConnectionTable[iFlagIndex][3*iTriangle+iCorner];
574
//we should only be accessing an edge if the edge was set.
575
ASSERT((1 << iVertex) & iEdgeFlags);
580
t.p[iCorner] = asEdgeVertex[iVertex];
583
indexedTriVec.push_back(t);
591
//OK, so we set up a network of triangle vertices which consist of edge numbers
592
//and a list of triangles which are the triplets of those numbers.
593
//Convert this into a
595
//Map that contains a list of triangles in the vector "indexedTriVec"
596
// which share a particular edge (or rather, position along that edge)
597
// First element is the edge index. Second element is the list of triangles
598
// who share this edge.
600
// We will need this when we do the vertex normals.
601
std::map<size_t,list<size_t> > edgeTriMap;
602
#pragma omp parallel for
603
for(size_t ui=0;ui<indexedTriVec.size(); ui++)
605
for(size_t uj=0;uj<3;uj++)
607
map<size_t,list<size_t> >::iterator it;
608
it = edgeTriMap.find((indexedTriVec[ui].p[uj] >>2 ) << 2);
609
if(it == edgeTriMap.end())
612
list<size_t> seedList;
613
seedList.push_back(ui);
616
make_pair((indexedTriVec[ui].p[uj] >>2 ) << 2,seedList));
621
it->second.push_back(ui);
628
//Generate the position points for each edge
629
map<size_t,Point3D> pointMap;
630
for(map<size_t,list<size_t> >::iterator it=edgeTriMap.begin();
631
it!=edgeTriMap.end(); ++it)
633
Point3D low,high,voxelFrameIntersection;
634
float lowF,highF,alpha;
636
if(pointMap.find((it->first>>2)<<2) != pointMap.end())
435
//Find the point of intersection of the surface with each edge
436
//Then find the normal to the surface at those points
437
Point3D asEdgeVertex[12];
438
for(int iEdge = 0; iEdge < 12; iEdge++)
440
//if there is an intersection on this edge
441
if(iEdgeFlags & (1<<iEdge))
444
fOffset =0.5;// interpLinear(vertexVal[ a2iEdgeConnection[iEdge][0] ],
445
// vertexVal[ a2iEdgeConnection[iEdge][1] ], isoValue);
447
ASSERT(fOffset >= -0.01 && fOffset < 1.01 );
449
asEdgeVertex[iEdge][0]= position[0] +
450
(a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][0] +
451
fOffset * a2fEdgeDirection[iEdge][0]) * gridSpacing[0];
453
asEdgeVertex[iEdge][1] = position[1]+
454
(a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][1] +
455
fOffset * a2fEdgeDirection[iEdge][1]) * gridSpacing[1];
456
asEdgeVertex[iEdge][2] = position[2] +
457
(a2fVertexOffset[ a2iEdgeConnection[iEdge][0] ][2] +
458
fOffset * a2fEdgeDirection[iEdge][2]) * gridSpacing[2];
461
ASSERT(boundC.containsPt(asEdgeVertex[iEdge] ));
462
//We will have to set normal later
467
//Store the triangles that were found. There can be up to five per cube
468
for(int iTriangle = 0; iTriangle < 5; iTriangle++)
470
if(a2iTriangleConnectionTable[iFlagIndex][3*iTriangle] < 0)
473
TriangleWithVertexNorm t;
474
for(int iCorner = 0; iCorner < 3; iCorner++)
477
iVertex = a2iTriangleConnectionTable[iFlagIndex][3*iTriangle+iCorner];
479
//we should only be accessing an edge if the edge was set.
480
ASSERT((1 << iVertex) & iEdgeFlags);
481
t.p[iCorner] = asEdgeVertex[iVertex];
482
//The mesh must be within the grid
483
ASSERT(boundC.containsPt(t.p[iCorner]));
486
if(!t.isDegenerate())
489
t.computeACWNormal(p);
491
//Assign pure normals,
492
for(unsigned int ui=0;ui<3;ui++)
639
//Low/high sides of edge's scalar values
640
v.getEdgeEndApproxVals(it->first,lowF,highF);
643
//Get the edge's low and high end node positions
644
v.getEdgeEnds((it->first>>2)<<2,low,high);
646
//OK, now we have that, lets use the values to "lever" the
647
//solution point note node locations for isosurface
648
if(fabs(highF-lowF) < sqrt(std::numeric_limits<float>::epsilon()))
650
//Prevent divide by zero
651
voxelFrameIntersection=(low+high)*0.5;
656
alpha= (isoValue- lowF) / (highF- lowF);
657
voxelFrameIntersection=low + (high-low)*alpha;
661
pointMap.insert(make_pair((it->first>>2)<<2,voxelFrameIntersection));
665
tVec.resize(indexedTriVec.size());
666
vector<size_t> popTris;
667
//Set all triangle verticies
668
#pragma omp parallel for
669
for(size_t ui=0;ui<tVec.size();ui++)
672
//Do a lookup of the edge point locations
673
// by mapping the edge indicies to the edge poitns
674
for(int uj=0;uj<3;uj++)
675
tVec[ui].p[uj] = pointMap.at((indexedTriVec[ui].p[uj]>>2)<<2);
677
if(tVec[ui].isDegenerate())
680
popTris.push_back(ui);
685
//Remove any degenerate triangles from both indexed and real maps
686
removeElements(popTris,tVec);
687
removeElements(popTris,indexedTriVec);
692
//set all triangle edge normals by inverse face area weighting.
693
// The idea is that big triangles don't affect the normal at the pooint
694
// as they are quite delocalised. Little triangles affect it mroe.
695
// This is entirely empirical
698
vector<Point3D> origNormal;
699
origNormal.resize(indexedTriVec.size());
700
#pragma omp parallel for
701
for(size_t ui=0;ui<indexedTriVec.size();ui++)
702
tVec[ui].safeComputeACWNormal(origNormal[ui]);
705
//Loop over all vertices again, then asssign a weighted
706
//normal in place of the original normal. Lets cheat and
709
for(map<size_t,Point3D>::iterator it=pointMap.begin();
710
it!=pointMap.end();++it)
711
it->second=Point3D(0,0,0);
713
//Construct the shared normals
714
float smallNum=sqrt(std::numeric_limits<float>::epsilon());
715
for(size_t ui=0;ui<indexedTriVec.size();ui++)
717
//For eachvertex in our current triangle
718
//update the weight mapping
720
weight=tVec[ui].computeArea();
722
if(weight > smallNum)
724
for(int uj=0;uj<3;uj++)
725
pointMap.at((indexedTriVec[ui].p[uj]>>2) <<2)+=origNormal[ui]*weight;
730
//re-normalise normals
731
for(map<size_t,Point3D>::iterator it=pointMap.begin();
732
it!=pointMap.end();++it)
734
if(it->second.sqrMag() > smallNum)
735
it->second.normalise();
737
it->second=Point3D(0,0,1);
740
//assign these normals to the vertices of each triangle
741
#pragma omp parallel for
742
for(size_t ui=0;ui<indexedTriVec.size();ui++)
744
for(unsigned int uj=0;uj<3;uj++)
745
tVec[ui].normal[uj] = pointMap.at((indexedTriVec[ui].p[uj]>>2)<<2);
752
//TODO: We could use something like triStripper
753
// to optimise this, rather than just build the raw triangles
754
// http://users.telenet.be/tfautre/softdev/tristripper/