This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp
Tamito Kajiyama a6a5ce4f7b More consolidation of the view map creation.
Made an attempt to fix "2D intersection out of range" warnings.
These warnings may cause "3D intersection out of range" warnings,
which often lead to a crash.
2010-02-11 23:26:22 +00:00

1050 lines
30 KiB
C++
Executable File

//
// Copyright (C) : Please refer to the COPYRIGHT file distributed
// with this source distribution.
//
// 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 2
// 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, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//
///////////////////////////////////////////////////////////////////////////////
#include <algorithm>
#include "ViewMapBuilder.h"
using namespace std;
ViewMap* ViewMapBuilder::BuildViewMap(WingedEdge& we, visibility_algo iAlgo, real epsilon) {
_ViewMap = new ViewMap;
_currentId = 1;
_currentFId = 0;
_currentSVertexId = 0;
// Builds initial view edges
computeInitialViewEdges(we);
// Detects cusps
computeCusps(_ViewMap);
// Compute intersections
ComputeIntersections(_ViewMap, sweep_line, epsilon);
// Compute visibility
ComputeEdgesVisibility(_ViewMap, iAlgo, _Grid, epsilon);
return _ViewMap;
}
void ViewMapBuilder::computeInitialViewEdges(WingedEdge& we)
{
vector<WShape*> wshapes = we.getWShapes();
SShape* psShape;
for (vector<WShape*>::const_iterator it = wshapes.begin();
it != wshapes.end();
it++) {
// create the embedding
psShape = new SShape;
psShape->setId((*it)->GetId());
psShape->setFrsMaterials((*it)->frs_materials()); // FIXME
// create the view shape
ViewShape * vshape = new ViewShape(psShape);
// add this view shape to the view map:
_ViewMap->AddViewShape(vshape);
_pViewEdgeBuilder->setCurrentViewId(_currentId); // we want to number the view edges in a unique way for the while scene.
_pViewEdgeBuilder->setCurrentFId(_currentFId); // we want to number the feature edges in a unique way for the while scene.
_pViewEdgeBuilder->setCurrentSVertexId(_currentFId); // we want to number the SVertex in a unique way for the while scene.
_pViewEdgeBuilder->BuildViewEdges(dynamic_cast<WXShape*>(*it), vshape,
_ViewMap->ViewEdges(),
_ViewMap->ViewVertices(),
_ViewMap->FEdges(),
_ViewMap->SVertices());
_currentId = _pViewEdgeBuilder->currentViewId()+1;
_currentFId = _pViewEdgeBuilder->currentFId()+1;
_currentSVertexId = _pViewEdgeBuilder->currentSVertexId()+1;
psShape->ComputeBBox();
}
}
void ViewMapBuilder::computeCusps(ViewMap *ioViewMap){
vector<ViewVertex*> newVVertices;
vector<ViewEdge*> newVEdges;
ViewMap::viewedges_container& vedges = ioViewMap->ViewEdges();
ViewMap::viewedges_container::iterator ve=vedges.begin(), veend=vedges.end();
for(;
ve!=veend;
++ve){
if((!((*ve)->getNature() & Nature::SILHOUETTE)) || (!((*ve)->fedgeA()->isSmooth())))
continue;
FEdge *fe = (*ve)->fedgeA();
FEdge * fefirst = fe;
bool first = true;
bool positive = true;
do{
FEdgeSmooth * fes = dynamic_cast<FEdgeSmooth*>(fe);
Vec3r A((fes)->vertexA()->point3d());
Vec3r B((fes)->vertexB()->point3d());
Vec3r AB(B-A);
AB.normalize();
Vec3r m((A+B)/2.0);
Vec3r crossP(AB^(fes)->normal());
crossP.normalize();
Vec3r viewvector;
if (_orthographicProjection) {
viewvector = Vec3r(0.0, 0.0, m.z()-_viewpoint.z());
} else {
viewvector = Vec3r(m-_viewpoint);
}
viewvector.normalize();
if(first){
if(((crossP)*(viewvector)) > 0)
positive = true;
else
positive = false;
first = false;
}
// If we're in a positive part, we need
// a stronger negative value to change
NonTVertex *cusp = 0;
if(positive){
if(((crossP)*(viewvector)) < -0.1){
// state changes
positive = false;
// creates and insert cusp
cusp = dynamic_cast<NonTVertex*>(ioViewMap->InsertViewVertex(fes->vertexA(), newVEdges));
if(cusp!=0)
cusp->setNature(cusp->getNature()|Nature::CUSP);
}
}else{
// If we're in a negative part, we need
// a stronger negative value to change
if(((crossP)*(viewvector)) > 0.1){
positive = true;
cusp = dynamic_cast<NonTVertex*>(ioViewMap->InsertViewVertex(fes->vertexA(), newVEdges));
if(cusp!=0)
cusp->setNature(cusp->getNature()|Nature::CUSP);
}
}
fe = fe->nextEdge();
}while((fe!=0) && (fe!=fefirst));
}
for(ve=newVEdges.begin(), veend=newVEdges.end();
ve!=veend;
++ve){
(*ve)->viewShape()->AddEdge(*ve);
vedges.push_back(*ve);
}
}
void ViewMapBuilder::ComputeEdgesVisibility(ViewMap *ioViewMap, visibility_algo iAlgo, Grid *iGrid, real epsilon)
{
if((iAlgo == ray_casting ||
iAlgo == ray_casting_fast ||
iAlgo == ray_casting_very_fast) && (NULL == iGrid))
{
cerr << "Error: can't cast ray, no grid defined" << endl;
return;
}
switch(iAlgo)
{
case ray_casting:
ComputeRayCastingVisibility(ioViewMap, iGrid, epsilon);
break;
case ray_casting_fast:
ComputeFastRayCastingVisibility(ioViewMap, iGrid, epsilon);
break;
case ray_casting_very_fast:
ComputeVeryFastRayCastingVisibility(ioViewMap, iGrid, epsilon);
break;
default:
break;
}
}
static const unsigned gProgressBarMaxSteps = 10;
static const unsigned gProgressBarMinSize = 2000;
void ViewMapBuilder::ComputeRayCastingVisibility(ViewMap *ioViewMap, Grid* iGrid, real epsilon)
{
vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
bool progressBarDisplay = false;
unsigned progressBarStep = 0;
unsigned vEdgesSize = vedges.size();
unsigned fEdgesSize = ioViewMap->FEdges().size();
if(_pProgressBar != NULL && fEdgesSize > gProgressBarMinSize) {
unsigned progressBarSteps = min(gProgressBarMaxSteps, vEdgesSize);
progressBarStep = vEdgesSize / progressBarSteps;
_pProgressBar->reset();
_pProgressBar->setLabelText("Computing Ray casting Visibility");
_pProgressBar->setTotalSteps(progressBarSteps);
_pProgressBar->setProgress(0);
progressBarDisplay = true;
}
unsigned counter = progressBarStep;
FEdge * fe, *festart;
int nSamples = 0;
vector<Polygon3r*> aFaces;
Polygon3r *aFace = 0;
unsigned tmpQI = 0;
unsigned qiClasses[256];
unsigned maxIndex, maxCard;
unsigned qiMajority;
static unsigned timestamp = 1;
for(vector<ViewEdge*>::iterator ve=vedges.begin(), veend=vedges.end();
ve!=veend;
ve++)
{
festart = (*ve)->fedgeA();
fe = (*ve)->fedgeA();
qiMajority = 1;
do {
qiMajority++;
fe = fe->nextEdge();
} while (fe && fe != festart);
qiMajority >>= 1;
tmpQI = 0;
maxIndex = 0;
maxCard = 0;
nSamples = 0;
fe = (*ve)->fedgeA();
memset(qiClasses, 0, 256 * sizeof(*qiClasses));
set<ViewShape*> occluders;
do
{
if((maxCard < qiMajority)) {
tmpQI = ComputeRayCastingVisibility(fe, iGrid, epsilon, occluders, &aFace, timestamp++);
if(tmpQI >= 256)
cerr << "Warning: too many occluding levels" << endl;
if (++qiClasses[tmpQI] > maxCard) {
maxCard = qiClasses[tmpQI];
maxIndex = tmpQI;
}
}
else
FindOccludee(fe, iGrid, epsilon, &aFace, timestamp++);
if(aFace) {
fe->setaFace(*aFace);
aFaces.push_back(aFace);
fe->setOccludeeEmpty(false);
}
else
fe->setOccludeeEmpty(true);
++nSamples;
fe = fe->nextEdge();
}
while((maxCard < qiMajority) && (0!=fe) && (fe!=festart));
// ViewEdge
// qi --
(*ve)->setQI(maxIndex);
// occluders --
for(set<ViewShape*>::iterator o=occluders.begin(), oend=occluders.end();
o!=oend;
++o)
(*ve)->AddOccluder((*o));
// occludee --
if(!aFaces.empty())
{
if(aFaces.size() <= (float)nSamples/2.f)
{
(*ve)->setaShape(0);
}
else
{
vector<Polygon3r*>::iterator p = aFaces.begin();
WFace * wface = (WFace*)((*p)->userdata);
ViewShape *vshape = ioViewMap->viewShape(wface->GetVertex(0)->shape()->GetId());
++p;
(*ve)->setaShape(vshape);
}
}
if(progressBarDisplay) {
counter--;
if (counter <= 0) {
counter = progressBarStep;
_pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
}
}
aFaces.clear();
}
}
void ViewMapBuilder::ComputeFastRayCastingVisibility(ViewMap *ioViewMap, Grid* iGrid, real epsilon)
{
vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
bool progressBarDisplay = false;
unsigned progressBarStep = 0;
unsigned vEdgesSize = vedges.size();
unsigned fEdgesSize = ioViewMap->FEdges().size();
if(_pProgressBar != NULL && fEdgesSize > gProgressBarMinSize) {
unsigned progressBarSteps = min(gProgressBarMaxSteps, vEdgesSize);
progressBarStep = vEdgesSize / progressBarSteps;
_pProgressBar->reset();
_pProgressBar->setLabelText("Computing Ray casting Visibility");
_pProgressBar->setTotalSteps(progressBarSteps);
_pProgressBar->setProgress(0);
progressBarDisplay = true;
}
unsigned counter = progressBarStep;
FEdge * fe, *festart;
unsigned nSamples = 0;
vector<Polygon3r*> aFaces;
Polygon3r *aFace = 0;
unsigned tmpQI = 0;
unsigned qiClasses[256];
unsigned maxIndex, maxCard;
unsigned qiMajority;
static unsigned timestamp = 1;
bool even_test;
for(vector<ViewEdge*>::iterator ve=vedges.begin(), veend=vedges.end();
ve!=veend;
ve++)
{
festart = (*ve)->fedgeA();
fe = (*ve)->fedgeA();
qiMajority = 1;
do {
qiMajority++;
fe = fe->nextEdge();
} while (fe && fe != festart);
if (qiMajority >= 4)
qiMajority >>= 2;
else
qiMajority = 1;
set<ViewShape*> occluders;
even_test = true;
maxIndex = 0;
maxCard = 0;
nSamples = 0;
memset(qiClasses, 0, 256 * sizeof(*qiClasses));
fe = (*ve)->fedgeA();
do
{
if (even_test)
{
if((maxCard < qiMajority)) {
tmpQI = ComputeRayCastingVisibility(fe, iGrid, epsilon, occluders, &aFace, timestamp++);
if(tmpQI >= 256)
cerr << "Warning: too many occluding levels" << endl;
if (++qiClasses[tmpQI] > maxCard) {
maxCard = qiClasses[tmpQI];
maxIndex = tmpQI;
}
}
else
FindOccludee(fe, iGrid, epsilon, &aFace, timestamp++);
if(aFace)
{
fe->setaFace(*aFace);
aFaces.push_back(aFace);
}
++nSamples;
even_test = false;
}
else
even_test = true;
fe = fe->nextEdge();
} while ((maxCard < qiMajority) && (0!=fe) && (fe!=festart));
(*ve)->setQI(maxIndex);
if(!aFaces.empty())
{
if(aFaces.size() < nSamples / 2)
{
(*ve)->setaShape(0);
}
else
{
vector<Polygon3r*>::iterator p = aFaces.begin();
WFace * wface = (WFace*)((*p)->userdata);
ViewShape *vshape = ioViewMap->viewShape(wface->GetVertex(0)->shape()->GetId());
++p;
// for(;
// p!=pend;
// ++p)
// {
// WFace *f = (WFace*)((*p)->userdata);
// ViewShape *vs = ioViewMap->viewShape(f->GetVertex(0)->shape()->GetId());
// if(vs != vshape)
// {
// sameShape = false;
// break;
// }
// }
// if(sameShape)
(*ve)->setaShape(vshape);
}
}
//(*ve)->setaFace(aFace);
if(progressBarDisplay) {
counter--;
if (counter <= 0) {
counter = progressBarStep;
_pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
}
}
aFaces.clear();
}
}
void ViewMapBuilder::ComputeVeryFastRayCastingVisibility(ViewMap *ioViewMap, Grid* iGrid, real epsilon)
{
vector<ViewEdge*>& vedges = ioViewMap->ViewEdges();
bool progressBarDisplay = false;
unsigned progressBarStep = 0;
unsigned vEdgesSize = vedges.size();
unsigned fEdgesSize = ioViewMap->FEdges().size();
if(_pProgressBar != NULL && fEdgesSize > gProgressBarMinSize) {
unsigned progressBarSteps = min(gProgressBarMaxSteps, vEdgesSize);
progressBarStep = vEdgesSize / progressBarSteps;
_pProgressBar->reset();
_pProgressBar->setLabelText("Computing Ray casting Visibility");
_pProgressBar->setTotalSteps(progressBarSteps);
_pProgressBar->setProgress(0);
progressBarDisplay = true;
}
unsigned counter = progressBarStep;
FEdge* fe;
unsigned qi = 0;
Polygon3r *aFace = 0;
static unsigned timestamp = 1;
for(vector<ViewEdge*>::iterator ve=vedges.begin(), veend=vedges.end();
ve!=veend;
ve++)
{
set<ViewShape*> occluders;
fe = (*ve)->fedgeA();
qi = ComputeRayCastingVisibility(fe, iGrid, epsilon, occluders, &aFace, timestamp++);
if(aFace)
{
fe->setaFace(*aFace);
WFace * wface = (WFace*)(aFace->userdata);
ViewShape *vshape = ioViewMap->viewShape(wface->GetVertex(0)->shape()->GetId());
(*ve)->setaShape(vshape);
}
else
{
(*ve)->setaShape(0);
}
(*ve)->setQI(qi);
if(progressBarDisplay) {
counter--;
if (counter <= 0) {
counter = progressBarStep;
_pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
}
}
}
}
void ViewMapBuilder::FindOccludee(FEdge *fe, Grid* iGrid, real epsilon, Polygon3r** oaPolygon, unsigned timestamp,
Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices)
{
WFace *face = 0;
if(fe->isSmooth()){
FEdgeSmooth * fes = dynamic_cast<FEdgeSmooth*>(fe);
face = (WFace*)fes->face();
}
OccludersSet occluders;
WFace * oface;
bool skipFace;
WVertex::incoming_edge_iterator ie;
OccludersSet::iterator p, pend;
*oaPolygon = 0;
if(((fe)->getNature() & Nature::SILHOUETTE) || ((fe)->getNature() & Nature::BORDER))
{
occluders.clear();
// we cast a ray from A in the same direction but looking behind
Vec3r v(-u[0],-u[1],-u[2]);
iGrid->castInfiniteRay(A, v, occluders, timestamp);
bool noIntersection = true;
real mint=FLT_MAX;
// we met some occluders, let us fill the aShape field
// with the first intersected occluder
for(p=occluders.begin(),pend=occluders.end();
p!=pend;
p++)
{
// check whether the edge and the polygon plane are coincident:
//-------------------------------------------------------------
//first let us compute the plane equation.
oface = (WFace*)(*p)->userdata;
Vec3r v1(((*p)->getVertices())[0]);
Vec3r normal((*p)->getNormal());
real d = -(v1 * normal);
real t,t_u,t_v;
if(0 != face)
{
skipFace = false;
if(face == oface)
continue;
if(faceVertices.empty())
continue;
for(vector<WVertex*>::iterator fv=faceVertices.begin(), fvend=faceVertices.end();
fv!=fvend;
++fv)
{
if((*fv)->isBoundary())
continue;
WVertex::incoming_edge_iterator iebegin=(*fv)->incoming_edges_begin();
WVertex::incoming_edge_iterator ieend=(*fv)->incoming_edges_end();
for(ie=iebegin;ie!=ieend; ++ie)
{
if((*ie) == 0)
continue;
WFace * sface = (*ie)->GetbFace();
if(sface == oface)
{
skipFace = true;
break;
}
}
if(skipFace)
break;
}
if(skipFace)
continue;
}
else
{
if(GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon))
continue;
}
if((*p)->rayIntersect(A, v, t,t_u,t_v))
{
if (fabs(v * normal) > 0.0001)
if ((t>0.0)) // && (t<1.0))
{
if (t<mint)
{
*oaPolygon = (*p);
mint = t;
noIntersection = false;
fe->setOccludeeIntersection(Vec3r(A+t*v));
}
}
}
}
if(noIntersection)
*oaPolygon = 0;
}
}
void ViewMapBuilder::FindOccludee(FEdge *fe, Grid* iGrid, real epsilon, Polygon3r** oaPolygon, unsigned timestamp)
{
OccludersSet occluders;
Vec3r A;
Vec3r edge;
Vec3r origin;
A = Vec3r(((fe)->vertexA()->point3D() + (fe)->vertexB()->point3D())/2.0);
edge = Vec3r((fe)->vertexB()->point3D()-(fe)->vertexA()->point3D());
origin = Vec3r((fe)->vertexA()->point3D());
Vec3r u;
if (_orthographicProjection) {
u = Vec3r(0.0, 0.0, _viewpoint.z()-A.z());
} else {
u = Vec3r(_viewpoint-A);
}
u.normalize();
if(A < iGrid->getOrigin())
cerr << "Warning: point is out of the grid for fedge " << fe->getId().getFirst() << "-" << fe->getId().getSecond() << endl;
vector<WVertex*> faceVertices;
WFace *face = 0;
if(fe->isSmooth()){
FEdgeSmooth * fes = dynamic_cast<FEdgeSmooth*>(fe);
face = (WFace*)fes->face();
}
if(0 != face)
face->RetrieveVertexList(faceVertices);
return FindOccludee(fe,iGrid, epsilon, oaPolygon, timestamp,
u, A, origin, edge, faceVertices);
}
int ViewMapBuilder::ComputeRayCastingVisibility(FEdge *fe, Grid* iGrid, real epsilon, set<ViewShape*>& oOccluders,
Polygon3r** oaPolygon, unsigned timestamp)
{
OccludersSet occluders;
int qi = 0;
Vec3r center;
Vec3r edge;
Vec3r origin;
center = fe->center3d();
edge = Vec3r(fe->vertexB()->point3D() - fe->vertexA()->point3D());
origin = Vec3r(fe->vertexA()->point3D());
//
// // Is the edge outside the view frustum ?
Vec3r gridOrigin(iGrid->getOrigin());
Vec3r gridExtremity(iGrid->getOrigin()+iGrid->gridSize());
if( (center.x() < gridOrigin.x()) || (center.y() < gridOrigin.y()) || (center.z() < gridOrigin.z())
||(center.x() > gridExtremity.x()) || (center.y() > gridExtremity.y()) || (center.z() > gridExtremity.z())){
cerr << "Warning: point is out of the grid for fedge " << fe->getId() << endl;
//return 0;
}
// Vec3r A(fe->vertexA()->point2d());
// Vec3r B(fe->vertexB()->point2d());
// int viewport[4];
// SilhouetteGeomEngine::retrieveViewport(viewport);
// if( (A.x() < viewport[0]) || (A.x() > viewport[2]) || (A.y() < viewport[1]) || (A.y() > viewport[3])
// ||(B.x() < viewport[0]) || (B.x() > viewport[2]) || (B.y() < viewport[1]) || (B.y() > viewport[3])){
// cerr << "Warning: point is out of the grid for fedge " << fe->getId() << endl;
// //return 0;
// }
Vec3r vp;
if (_orthographicProjection) {
vp = Vec3r(center.x(), center.y(), _viewpoint.z());
} else {
vp = Vec3r(_viewpoint);
}
Vec3r u(vp - center);
real raylength = u.norm();
u.normalize();
//cout << "grid origin " << iGrid->getOrigin().x() << "," << iGrid->getOrigin().y() << "," << iGrid->getOrigin().z() << endl;
//cout << "center " << center.x() << "," << center.y() << "," << center.z() << endl;
iGrid->castRay(center, vp, occluders, timestamp);
WFace *face = 0;
if(fe->isSmooth()){
FEdgeSmooth * fes = dynamic_cast<FEdgeSmooth*>(fe);
face = (WFace*)fes->face();
}
vector<WVertex*> faceVertices;
WVertex::incoming_edge_iterator ie;
WFace * oface;
bool skipFace;
OccludersSet::iterator p, pend;
if(face)
face->RetrieveVertexList(faceVertices);
for(p=occluders.begin(),pend=occluders.end();
p!=pend;
p++)
{
// If we're dealing with an exact silhouette, check whether
// we must take care of this occluder of not.
// (Indeed, we don't consider the occluders that
// share at least one vertex with the face containing
// this edge).
//-----------
oface = (WFace*)(*p)->userdata;
Vec3r v1(((*p)->getVertices())[0]);
Vec3r normal((*p)->getNormal());
real d = -(v1 * normal);
real t, t_u, t_v;
if(0 != face)
{
skipFace = false;
if(face == oface)
continue;
for(vector<WVertex*>::iterator fv=faceVertices.begin(), fvend=faceVertices.end();
fv!=fvend;
++fv)
{
if((*fv)->isBoundary())
continue;
WVertex::incoming_edge_iterator iebegin=(*fv)->incoming_edges_begin();
WVertex::incoming_edge_iterator ieend=(*fv)->incoming_edges_end();
for(ie=iebegin;ie!=ieend; ++ie)
{
if((*ie) == 0)
continue;
WFace * sface = (*ie)->GetbFace();
//WFace * sfacea = (*ie)->GetaFace();
//if((sface == oface) || (sfacea == oface))
if(sface == oface)
{
skipFace = true;
break;
}
}
if(skipFace)
break;
}
if(skipFace)
continue;
}
else
{
// check whether the edge and the polygon plane are coincident:
//-------------------------------------------------------------
//first let us compute the plane equation.
if(GeomUtils::COINCIDENT == GeomUtils::intersectRayPlane(origin, edge, normal, d, t, epsilon))
continue;
}
if((*p)->rayIntersect(center, u, t, t_u, t_v))
{
if (fabs(u * normal) > 0.0001)
if ((t>0.0) && (t<raylength))
{
WFace *f = (WFace*)((*p)->userdata);
ViewShape *vshape = _ViewMap->viewShape(f->GetVertex(0)->shape()->GetId());
oOccluders.insert(vshape);
++qi;
if(!_EnableQI)
break;
}
}
}
// Find occludee
FindOccludee(fe,iGrid, epsilon, oaPolygon, timestamp,
u, center, edge, origin, faceVertices);
return qi;
}
void ViewMapBuilder::ComputeIntersections(ViewMap *ioViewMap, intersection_algo iAlgo, real epsilon)
{
switch(iAlgo)
{
case sweep_line:
ComputeSweepLineIntersections(ioViewMap, epsilon);
break;
default:
break;
}
ViewMap::viewvertices_container& vvertices = ioViewMap->ViewVertices();
for(ViewMap::viewvertices_container::iterator vv=vvertices.begin(), vvend=vvertices.end();
vv!=vvend;
++vv)
{
if((*vv)->getNature() == Nature::T_VERTEX)
{
TVertex *tvertex = (TVertex*)(*vv);
cout << "TVertex " << tvertex->getId() << " has :" << endl;
cout << "FrontEdgeA: " << tvertex->frontEdgeA().first << endl;
cout << "FrontEdgeB: " << tvertex->frontEdgeB().first << endl;
cout << "BackEdgeA: " << tvertex->backEdgeA().first << endl;
cout << "BackEdgeB: " << tvertex->backEdgeB().first << endl << endl;
}
}
}
struct less_SVertex2D : public binary_function<SVertex*, SVertex*, bool>
{
real epsilon;
less_SVertex2D(real eps)
: binary_function<SVertex*,SVertex*,bool>()
{
epsilon = eps;
}
bool operator()(SVertex* x, SVertex* y)
{
Vec3r A = x->point2D();
Vec3r B = y->point2D();
for(unsigned int i=0; i<3; i++)
{
if((fabs(A[i] - B[i])) < epsilon)
continue;
if(A[i] < B[i])
return true;
if(A[i] > B[i])
return false;
}
return false;
}
};
typedef Segment<FEdge*,Vec3r > segment;
typedef Intersection<segment> intersection;
struct less_Intersection : public binary_function<intersection*, intersection*, bool>
{
segment *edge;
less_Intersection(segment *iEdge)
: binary_function<intersection*,intersection*,bool>()
{
edge = iEdge;
}
bool operator()(intersection* x, intersection* y)
{
real tx = x->getParameter(edge);
real ty = y->getParameter(edge);
if(tx > ty)
return true;
return false;
}
};
struct silhouette_binary_rule : public binary_rule<segment,segment>
{
silhouette_binary_rule() : binary_rule<segment,segment>() {}
virtual bool operator() (segment& s1, segment& s2)
{
FEdge * f1 = s1.edge();
FEdge * f2 = s2.edge();
if((!(((f1)->getNature() & Nature::SILHOUETTE) || ((f1)->getNature() & Nature::BORDER))) && (!(((f2)->getNature() & Nature::SILHOUETTE) || ((f2)->getNature() & Nature::BORDER))))
return false;
return true;
}
};
void ViewMapBuilder::ComputeSweepLineIntersections(ViewMap *ioViewMap, real epsilon)
{
vector<SVertex*>& svertices = ioViewMap->SVertices();
bool progressBarDisplay = false;
unsigned sVerticesSize = svertices.size();
unsigned fEdgesSize = ioViewMap->FEdges().size();
// ViewMap::fedges_container& fedges = ioViewMap->FEdges();
// for(ViewMap::fedges_container::const_iterator f=fedges.begin(), end=fedges.end();
// f!=end;
// ++f){
// cout << (*f)->aMaterialIndex() << "-" << (*f)->bMaterialIndex() << endl;
// }
unsigned progressBarStep = 0;
if(_pProgressBar != NULL && fEdgesSize > gProgressBarMinSize) {
unsigned progressBarSteps = min(gProgressBarMaxSteps, sVerticesSize);
progressBarStep = sVerticesSize / progressBarSteps;
_pProgressBar->reset();
_pProgressBar->setLabelText("Computing Sweep Line Intersections");
_pProgressBar->setTotalSteps(progressBarSteps);
_pProgressBar->setProgress(0);
progressBarDisplay = true;
}
unsigned counter = progressBarStep;
sort(svertices.begin(), svertices.end(), less_SVertex2D(epsilon));
SweepLine<FEdge*,Vec3r> SL;
vector<FEdge*>& ioEdges = ioViewMap->FEdges();
vector<segment* > segments;
vector<FEdge*>::iterator fe,fend;
for(fe=ioEdges.begin(), fend=ioEdges.end();
fe!=fend;
fe++)
{
segment * s = new segment((*fe), (*fe)->vertexA()->point2D(), (*fe)->vertexB()->point2D());
(*fe)->userdata = s;
segments.push_back(s);
}
vector<segment*> vsegments;
for(vector<SVertex*>::iterator sv=svertices.begin(),svend=svertices.end();
sv!=svend;
sv++)
{
const vector<FEdge*>& vedges = (*sv)->fedges();
for(vector<FEdge*>::const_iterator sve=vedges.begin(), sveend=vedges.end();
sve!=sveend;
sve++)
{
vsegments.push_back((segment*)((*sve)->userdata));
}
Vec3r evt((*sv)->point2D());
silhouette_binary_rule sbr;
SL.process(evt, vsegments, sbr, epsilon);
if(progressBarDisplay) {
counter--;
if (counter <= 0) {
counter = progressBarStep;
_pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
}
}
vsegments.clear();
}
// reset userdata:
for(fe=ioEdges.begin(), fend=ioEdges.end();
fe!=fend;
fe++)
(*fe)->userdata = NULL;
// list containing the new edges resulting from splitting operations.
vector<FEdge*> newEdges;
// retrieve the intersected edges:
vector<segment* >& iedges = SL.intersectedEdges();
// retrieve the intersections:
vector<intersection*>& intersections = SL.intersections();
int id=0;
// create a view vertex for each intersection and linked this one
// with the intersection object
vector<intersection*>::iterator i, iend;
for(i=intersections.begin(),iend=intersections.end();
i!=iend;
i++)
{
FEdge *fA = (*i)->EdgeA->edge();
FEdge *fB = (*i)->EdgeB->edge();
Vec3r A1 = fA->vertexA()->point3D();
Vec3r A2 = fA->vertexB()->point3D();
Vec3r B1 = fB->vertexA()->point3D();
Vec3r B2 = fB->vertexB()->point3D();
Vec3r a1 = fA->vertexA()->point2D();
Vec3r a2 = fA->vertexB()->point2D();
Vec3r b1 = fB->vertexA()->point2D();
Vec3r b2 = fB->vertexB()->point2D();
real ta = (*i)->tA;
real tb = (*i)->tB;
if((ta < -epsilon) || (ta > 1+epsilon))
cerr << "Warning: 2D intersection out of range for edge " << fA->vertexA()->getId() << " - " << fA->vertexB()->getId() << endl;
if((tb < -epsilon) || (tb > 1+epsilon))
cerr << "Warning: 2D intersection out of range for edge " << fB->vertexA()->getId() << " - " << fB->vertexB()->getId() << endl;
real Ta = SilhouetteGeomEngine::ImageToWorldParameter(fA, ta);
real Tb = SilhouetteGeomEngine::ImageToWorldParameter(fB, tb);
if((Ta < -epsilon) || (Ta > 1+epsilon))
cerr << "Warning: 3D intersection out of range for edge " << fA->vertexA()->getId() << " - " << fA->vertexB()->getId() << endl;
if((Tb < -epsilon) || (Tb > 1+epsilon))
cerr << "Warning: 3D intersection out of range for edge " << fB->vertexA()->getId() << " - " << fB->vertexB()->getId() << endl;
TVertex * tvertex = ioViewMap->CreateTVertex(Vec3r(A1 + Ta*(A2-A1)), Vec3r(a1 + ta*(a2-a1)), fA,
Vec3r(B1 + Tb*(B2-B1)), Vec3r(b1 + tb*(b2-b1)), fB, id);
(*i)->userdata = tvertex;
++id;
}
progressBarStep = 0;
if(progressBarDisplay) {
unsigned iEdgesSize = iedges.size();
unsigned progressBarSteps = min(gProgressBarMaxSteps, iEdgesSize);
progressBarStep = iEdgesSize / progressBarSteps;
_pProgressBar->reset();
_pProgressBar->setLabelText("Splitting intersected edges");
_pProgressBar->setTotalSteps(progressBarSteps);
_pProgressBar->setProgress(0);
}
counter = progressBarStep;
vector<TVertex*> edgeVVertices;
vector<ViewEdge*> newVEdges;
vector<segment* >::iterator s, send;
for(s=iedges.begin(),send=iedges.end();
s!=send;
s++)
{
edgeVVertices.clear();
newEdges.clear();
newVEdges.clear();
FEdge* fedge = (*s)->edge();
ViewEdge *vEdge = fedge->viewedge();
ViewShape *shape = vEdge->viewShape();
vector<intersection*>& eIntersections = (*s)->intersections();
// we first need to sort these intersections from farther to closer to A
sort(eIntersections.begin(), eIntersections.end(), less_Intersection(*s));
for(i=eIntersections.begin(),iend=eIntersections.end();
i!=iend;
i++)
edgeVVertices.push_back((TVertex*)(*i)->userdata);
shape->SplitEdge(fedge, edgeVVertices, ioViewMap->FEdges(), ioViewMap->ViewEdges());
if(progressBarDisplay) {
counter--;
if (counter <= 0) {
counter = progressBarStep;
_pProgressBar->setProgress(_pProgressBar->getProgress() + 1);
}
}
}
// reset userdata:
for(fe=ioEdges.begin(), fend=ioEdges.end();
fe!=fend;
fe++)
(*fe)->userdata = NULL;
// delete segments
// if(!segments.empty()){
// for(s=segments.begin(),send=segments.end();
// s!=send;
// s++){
// delete *s;
// }
// segments.clear();
// }
}