diff options
Diffstat (limited to 'source/blender/freestyle/intern/view_map')
26 files changed, 12897 insertions, 0 deletions
diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp new file mode 100755 index 00000000000..0551fd3ac15 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp @@ -0,0 +1,700 @@ + +// +// 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 "FEdgeXDetector.h" +#include "float.h" +#include "../geometry/GeomUtils.h" +#include <math.h> +#include "../geometry/normal_cycle.h" + +void FEdgeXDetector::processShapes(WingedEdge& we) { + bool progressBarDisplay = false; + Vec3r Min, Max; + vector<WShape*> wshapes = we.getWShapes(); + WXShape * wxs; + + if(_pProgressBar != NULL) { + _pProgressBar->reset(); + _pProgressBar->setLabelText("Detecting feature lines"); + _pProgressBar->setTotalSteps(wshapes.size() * 3); + _pProgressBar->setProgress(0); + progressBarDisplay = true; + } + + for(vector<WShape*>::const_iterator it = wshapes.begin(); + it != wshapes.end(); + it++){ + wxs = dynamic_cast<WXShape*>(*it); + wxs->bbox(Min, Max); + _bbox_diagonal = (Max-Min).norm(); + if(_changes){ + vector<WFace*>& wfaces = wxs->GetFaceList(); + for(vector<WFace*>::iterator wf=wfaces.begin(), wfend=wfaces.end(); + wf!=wfend; + ++wf){ + WXFace* wxf = dynamic_cast<WXFace*>(*wf); + wxf->Clear(); + } + _computeViewIndependant = true; + } else if (!(wxs)->getComputeViewIndependantFlag()) { + wxs->Reset(); + _computeViewIndependant = false; + } else { + _computeViewIndependant = true; + } + preProcessShape(wxs); + if (progressBarDisplay) + _pProgressBar->setProgress(_pProgressBar->getProgress() + 1); + processBorderShape(wxs); + processCreaseShape(wxs); + if(_computeRidgesAndValleys) + processRidgesAndValleysShape(wxs); + if(_computeSuggestiveContours) + processSuggestiveContourShape(wxs); + processSilhouetteShape(wxs); + if (progressBarDisplay) + _pProgressBar->setProgress(_pProgressBar->getProgress() + 1); + + // build smooth edges: + buildSmoothEdges(wxs); + + // Post processing for suggestive contours + if(_computeSuggestiveContours) + postProcessSuggestiveContourShape(wxs); + if (progressBarDisplay) + _pProgressBar->setProgress(_pProgressBar->getProgress() + 1); + + wxs->setComputeViewIndependantFlag(false); + _computeViewIndependant = false; + _changes = false; + + // reset user data + (*it)->ResetUserData(); + } +} + +// GENERAL STUFF +//////////////// +void FEdgeXDetector::preProcessShape(WXShape* iWShape) { + _meanK1 = 0; + _meanKr = 0; + _minK1 = FLT_MAX; + _maxK1 = -FLT_MAX; + _minKr = FLT_MAX; + _maxKr = -FLT_MAX; + _nPoints = 0; + _meanEdgeSize = iWShape->getMeanEdgeSize(); + + vector<WFace*>& wfaces = iWShape->GetFaceList(); + vector<WFace*>::iterator f,fend; + // view dependant stuff + for(f=wfaces.begin(), fend=wfaces.end(); + f!=fend; + ++f){ + preProcessFace((WXFace*)(*f)); + } + + vector<WVertex*>& wvertices = iWShape->getVertexList(); + for(vector<WVertex*>::iterator wv=wvertices.begin(), wvend=wvertices.end(); + wv!=wvend; + ++wv){ + // Compute curvatures + WXVertex * wxv = dynamic_cast<WXVertex*>(*wv); + computeCurvatures(wxv); + } + _meanK1 /= (real)(_nPoints); + _meanKr /= (real)(_nPoints); +} + +void FEdgeXDetector::preProcessFace(WXFace *iFace){ + Vec3r firstPoint = iFace->GetVertex(0)->GetVertex(); + Vec3r N = iFace->GetNormal(); + + // Compute the dot product between V (=_Viewpoint - firstPoint) and N: + Vec3r V; + if (_orthographicProjection) { + V = Vec3r(0.0, 0.0, _Viewpoint.z() - firstPoint.z()); + } else { + V = Vec3r(_Viewpoint - firstPoint); + } + N.normalize(); + V.normalize(); + iFace->setDotP(N * V); + + // compute the distance between the face center and the viewpoint: + if (_orthographicProjection) { + iFace->setZ(iFace->center().z() - _Viewpoint.z()); + } else { + Vec3r dist_vec(iFace->center() - _Viewpoint); + iFace->setZ(dist_vec.norm()); + } +} + +void FEdgeXDetector::computeCurvatures(WXVertex *vertex){ + // CURVATURE LAYER + // store all the curvature datas for each vertex + + //soc unused - real K1, K2 + real cos2theta, sin2theta; + Vec3r e1, n, v; + // one vertex curvature info : + CurvatureInfo *C; + float radius = _sphereRadius*_meanEdgeSize; + + // view independant stuff + if(_computeViewIndependant){ + C = new CurvatureInfo(); + vertex->setCurvatures(C); + OGF::NormalCycle ncycle ; + ncycle.begin() ; + if(radius > 0) { + OGF::compute_curvature_tensor(vertex, radius, ncycle) ; + } else { + OGF::compute_curvature_tensor_one_ring(vertex, ncycle) ; + } + ncycle.end() ; + C->K1 = ncycle.kmin(); + C->K2 = ncycle.kmax(); + C->e1 = ncycle.Kmax(); //ncycle.kmin() * ncycle.Kmax(); + C->e2 = ncycle.Kmin(); //ncycle.kmax() * ncycle.Kmin() ; + + real absK1 = fabs(C->K1); + _meanK1 += absK1; + if(absK1 > _maxK1) + _maxK1 = absK1; + if(absK1 < _minK1) + _minK1 = absK1; + } + // view dependant + C = vertex->curvatures(); + if(C == 0) + return; + + // compute radial curvature : + n = C->e1 ^ C->e2; + if (_orthographicProjection) { + v = Vec3r(0.0, 0.0, _Viewpoint.z() - vertex->GetVertex().z()); + } else { + v = Vec3r(_Viewpoint - vertex->GetVertex()); + } + C->er = v - (v * n) * n; + C->er.normalize(); + e1 = C->e1; + e1.normalize(); + cos2theta = C->er * e1; + cos2theta *= cos2theta; + sin2theta = 1 - cos2theta; + C->Kr = C->K1 * cos2theta + C->K2 * sin2theta; + real absKr = fabs(C->Kr); + _meanKr += absKr; + if(absKr > _maxKr) + _maxKr = absKr; + if(absKr < _minKr) + _minKr = absKr; + + ++_nPoints; +} + +// SILHOUETTE +///////////// +void FEdgeXDetector::processSilhouetteShape(WXShape* iWShape) { + // Make a first pass on every polygons in order + // to compute all their silhouette relative values: + //------------------------------------------------ + vector<WFace*>& wfaces = iWShape->GetFaceList(); + vector<WFace*>::iterator f,fend; + for(f=wfaces.begin(), fend=wfaces.end(); + f!=fend; + ++f) + { + ProcessSilhouetteFace((WXFace*)(*f)); + } + + // Make a pass on the edges to detect + // the silhouette edges that are not smooth + // -------------------- + vector<WEdge*>::iterator we, weend; + vector<WEdge*> &wedges = iWShape->getEdgeList(); + for(we=wedges.begin(), weend=wedges.end(); + we!=weend; + ++we) + { + ProcessSilhouetteEdge((WXEdge*)(*we)); + } +} + +void FEdgeXDetector::ProcessSilhouetteFace(WXFace *iFace) +{ + + // SILHOUETTE LAYER + Vec3r normal; + // Compute the dot products between View direction and N at each vertex + // of the face: + Vec3r point; + int closestPointId = 0; + real dist, minDist = FLT_MAX; + int numVertices = iFace->numberOfVertices(); + WXFaceLayer * faceLayer = new WXFaceLayer(iFace, Nature::SILHOUETTE, true); + for(int i=0; i<numVertices; i++){ + point = iFace->GetVertex(i)->GetVertex(); + normal = iFace->GetVertexNormal(i); + normal.normalize(); + Vec3r V; + if (_orthographicProjection) { + V = Vec3r(0.0, 0.0, _Viewpoint.z() - point.z()); + } else { + V = Vec3r(_Viewpoint - point); + } + V.normalize(); + real d = normal * V; + faceLayer->PushDotP(d); + // Find the point the closest to the viewpoint + if (_orthographicProjection) { + dist = point.z() - _Viewpoint.z(); + } else { + Vec3r dist_vec(point - _Viewpoint); + dist = dist_vec.norm(); + } + if(dist < minDist) { + minDist = dist; + closestPointId = i; + } + } + // Set the closest point id: + faceLayer->setClosestPointIndex(closestPointId); + // Add this layer to the face: + iFace->AddSmoothLayer(faceLayer); +} + +void FEdgeXDetector::ProcessSilhouetteEdge(WXEdge *iEdge) +{ + if(iEdge->nature() & Nature::BORDER) + return; + // SILHOUETTE ? + //------------- + WXFace * fA = (WXFace *)iEdge->GetaOEdge()->GetaFace(); + WXFace * fB = (WXFace *)iEdge->GetaOEdge()->GetbFace(); + + if((fA->front())^(fB->front())){ // fA->visible XOR fB->visible (true if one is 0 and the other is 1) + // The only edges we want to set as silhouette edges in this + // way are the ones with 2 different normals for 1 vertex + // for these two faces + //-------------------- + // In reality we only test the normals for 1 of the 2 vertices. + if(fA->GetVertexNormal(iEdge->GetaVertex()) == fB->GetVertexNormal(iEdge->GetaVertex())) + return; + iEdge->AddNature(Nature::SILHOUETTE); + if(fB->front()) + iEdge->setOrder(1); + else + iEdge->setOrder(-1); + } +} + + +// BORDER +///////// +void FEdgeXDetector::processBorderShape(WXShape* iWShape) { + + if(!_computeViewIndependant) + return; + // Make a pass on the edges to detect + // the BORDER + // -------------------- + vector<WEdge*>::iterator we, weend; + vector<WEdge*> &wedges = iWShape->getEdgeList(); + for(we=wedges.begin(), weend=wedges.end(); + we!=weend; + ++we){ + ProcessBorderEdge((WXEdge*)(*we)); + } +} + +void FEdgeXDetector::ProcessBorderEdge(WXEdge *iEdge) +{ + // first check whether it is a border edge: + // BORDER ? + //--------- + if(iEdge->GetaFace() == 0){ + // it is a border edge + iEdge->AddNature(Nature::BORDER); + } +} + + +// CREASE +///////// +void FEdgeXDetector::processCreaseShape(WXShape* iWShape) { + if(!_computeViewIndependant) + return; + + // Make a pass on the edges to detect + // the CREASE + // -------------------- + vector<WEdge*>::iterator we, weend; + vector<WEdge*> &wedges = iWShape->getEdgeList(); + for(we=wedges.begin(), weend=wedges.end(); + we!=weend; + ++we){ + ProcessCreaseEdge((WXEdge*)(*we)); + } +} + +void FEdgeXDetector::ProcessCreaseEdge(WXEdge *iEdge) +{ + // CREASE ? + //--------- + if(iEdge->nature() & Nature::BORDER) + return; + WXFace * fA = (WXFace *)iEdge->GetaOEdge()->GetaFace(); + WXFace * fB = (WXFace *)iEdge->GetaOEdge()->GetbFace(); + + WVertex * aVertex = iEdge->GetaVertex(); + if((fA->GetVertexNormal(aVertex) * fB->GetVertexNormal(aVertex)) <= 0.7) // angle of 140 degrees + iEdge->AddNature(Nature::CREASE); +} + +// RIDGES AND VALLEYS +///////////////////// + +void FEdgeXDetector::processRidgesAndValleysShape(WXShape* iWShape) { + // Don't forget to add the built layer to the face at the end + // of the ProcessFace: + //iFace->AddSmoothLayer(faceLayer); + + if((!_computeViewIndependant)) + return; + + // Here the curvatures must already have been computed + vector<WFace*>& wfaces = iWShape->GetFaceList(); + vector<WFace*>::iterator f, fend; + for(f=wfaces.begin(), fend=wfaces.end(); + f!=fend; + ++f) + { + ProcessRidgeFace((WXFace*)(*f)); + } +} + + +// RIDGES +///////// + +void FEdgeXDetector::ProcessRidgeFace(WXFace *iFace) +{ + WXFaceLayer * flayer = new WXFaceLayer(iFace, Nature::RIDGE|Nature::VALLEY, false); + iFace->AddSmoothLayer(flayer); + + unsigned int numVertices = iFace->numberOfVertices(); + for(unsigned int i=0; i<numVertices; ++i){ + WVertex *wv = iFace->GetVertex(i); + WXVertex * wxv = dynamic_cast<WXVertex*>(wv); + flayer->PushDotP(wxv->curvatures()->K1); + } + + real threshold = 0; + //real threshold = _maxK1 - (_maxK1-_meanK1)/20.0; + + if(flayer->nPosDotP()!=numVertices){ + if((fabs(flayer->dotP(0)) < threshold) && (fabs(flayer->dotP(1)) < threshold) && (fabs(flayer->dotP(2)) < threshold)){ + flayer->ReplaceDotP(0, 0); + flayer->ReplaceDotP(1, 0); + flayer->ReplaceDotP(2, 0); + } + } +} + +// void FEdgeXDetector::ProcessRidgeFace(WXFace *iFace) +// { + +// // RIDGE LAYER +// // compute the RidgeFunction, that is the derivative of the ppal curvature +// // along e1 at each vertex of the face + +// WVertex *v; +// Vec3r v1v2; +// real t; +// vector<WXFaceLayer*> SmoothLayers; +// WXFaceLayer *faceLayer; +// Face_Curvature_Info *layer_info; +// real K1_a(0), K1_b(0); +// Vec3r Inter_a, Inter_b; + +// // find the ridge layer of the face +// iFace->retrieveSmoothLayers(Nature::RIDGE, SmoothLayers); +// if(SmoothLayers.size()!=1) +// return; +// faceLayer = SmoothLayers[0]; +// // retrieve the curvature info of this layer +// layer_info = (Face_Curvature_Info *)faceLayer->userdata; + +// int numVertices = iFace->numberOfVertices(); +// for(int i=0; i<numVertices; i++){ +// v = iFace->GetVertex(i); +// // vec_curvature_info[i] contains the curvature info of this vertex +// Vec3r e2 = layer_info->vec_curvature_info[i]->K2*layer_info->vec_curvature_info[i]->e2; +// Vec3r e1 = layer_info->vec_curvature_info[i]->K1*layer_info->vec_curvature_info[i]->e1; +// e2.normalize(); + +// WVertex::face_iterator fit = v->faces_begin(); +// WVertex::face_iterator fitend = v->faces_end(); +// for(; fit!=fitend; ++fit){ +// WXFace * wxf = dynamic_cast<WXFace*>(*fit); +// WOEdge * oppositeEdge; +// if(!(wxf->getOppositeEdge(v, oppositeEdge))) +// continue; +// v1v2 = oppositeEdge->GetbVertex()->GetVertex() - oppositeEdge->GetaVertex()->GetVertex(); +// GeomUtils::intersection_test res; +// res = GeomUtils::intersectRayPlane(oppositeEdge->GetaVertex()->GetVertex(), v1v2, +// e2, -(v->GetVertex()*e2), +// t,1.e-06); +// if((res == GeomUtils::DO_INTERSECT) && (t>=0.0) && (t<=1.0)){ +// vector<WXFaceLayer*> second_ridge_layer; +// wxf->retrieveSmoothLayers(Nature::RIDGE, second_ridge_layer); +// if(second_ridge_layer.size()!=1) +// continue; +// Face_Curvature_Info *second_layer_info = (Face_Curvature_Info*)second_ridge_layer[0]->userdata; + +// unsigned index1 = wxf->GetIndex(oppositeEdge->GetaVertex()); +// unsigned index2 = wxf->GetIndex(oppositeEdge->GetbVertex()); +// real K1_1 = second_layer_info->vec_curvature_info[index1]->K1; +// real K1_2 = second_layer_info->vec_curvature_info[index2]->K1; +// real K1 = (1.0-t)*K1_1 + t*K1_2; +// Vec3r inter((1.0-t)*oppositeEdge->GetaVertex()->GetVertex() + t*oppositeEdge->GetbVertex()->GetVertex()); +// Vec3r vtmp(inter - v->GetVertex()); +// // is it K1_a or K1_b ? +// if(vtmp*e1 > 0){ +// K1_b = K1; +// Inter_b = inter; +// }else{ +// K1_a = K1; +// Inter_a = inter; +// } +// } +// } +// // Once we have K1 along the the ppal direction +// // compute the derivative : K1b - K1a +// // put it in DotP +// //real d = fabs(K1_b)-fabs(K1_a); +// real d = 0; +// real threshold = _meanK1 + (_maxK1-_meanK1)/7.0; +// //real threshold = _meanK1; +// //if((fabs(K1_b) > threshold) || ((fabs(K1_a) > threshold))) +// d = (K1_b)-(K1_a)/(Inter_b-Inter_a).norm(); +// faceLayer->PushDotP(d); +// //faceLayer->PushDotP(layer_info->vec_curvature_info[i]->K1); +// } + +// // Make the values relevant by checking whether all principal +// // directions have the "same" direction: +// Vec3r e0((layer_info->vec_curvature_info[0]->K1*layer_info->vec_curvature_info[0]->e1)); +// e0.normalize(); +// Vec3r e1((layer_info->vec_curvature_info[1]->K1*layer_info->vec_curvature_info[1]->e1)); +// e1.normalize(); +// Vec3r e2((layer_info->vec_curvature_info[2]->K1*layer_info->vec_curvature_info[2]->e1)); +// e2.normalize(); +// if (e0 * e1 < 0) +// // invert dotP[1] +// faceLayer->ReplaceDotP(1, -faceLayer->dotP(1)); +// if (e0 * e2 < 0) +// // invert dotP[2] +// faceLayer->ReplaceDotP(2, -faceLayer->dotP(2)); + +// // remove the weakest values; +// //real minDiff = (_maxK1 - _minK1)/10.0; +// // real minDiff = _meanK1; +// // if((faceLayer->dotP(0) < minDiff) && (faceLayer->dotP(1) < minDiff) && (faceLayer->dotP(2) < minDiff)){ +// // faceLayer->ReplaceDotP(0, 0); +// // faceLayer->ReplaceDotP(1, 0); +// // faceLayer->ReplaceDotP(2, 0); +// // } +// } + +// SUGGESTIVE CONTOURS +////////////////////// + +void FEdgeXDetector::processSuggestiveContourShape(WXShape* iWShape) { + + // Here the curvatures must already have been computed + vector<WFace*>& wfaces = iWShape->GetFaceList(); + vector<WFace*>::iterator f, fend; + for(f=wfaces.begin(), fend=wfaces.end(); + f!=fend; + ++f) + { + ProcessSuggestiveContourFace((WXFace*)(*f)); + } +} + +void FEdgeXDetector::ProcessSuggestiveContourFace(WXFace *iFace) +{ + WXFaceLayer *faceLayer = new WXFaceLayer(iFace, Nature::SUGGESTIVE_CONTOUR, true); + iFace->AddSmoothLayer(faceLayer); + + unsigned int numVertices = iFace->numberOfVertices(); + for(unsigned int i=0; i<numVertices; ++i){ + WVertex *wv = iFace->GetVertex(i); + WXVertex * wxv = dynamic_cast<WXVertex*>(wv); + faceLayer->PushDotP(wxv->curvatures()->Kr); + } + + // FIXME: find a more clever way to compute the threshold +// real threshold = _meanKr; +// if(faceLayer->nPosDotP()!=numVertices){ +// if((fabs(faceLayer->dotP(0)) < threshold) && (fabs(faceLayer->dotP(1)) < threshold) && (fabs(faceLayer->dotP(2)) < threshold)){ +// faceLayer->ReplaceDotP(0, 0); +// faceLayer->ReplaceDotP(1, 0); +// faceLayer->ReplaceDotP(2, 0); +// } +// } +} + +void FEdgeXDetector::postProcessSuggestiveContourShape(WXShape* iShape) { + vector<WFace*>& wfaces = iShape->GetFaceList(); + vector<WFace*>::iterator f, fend; + for(f=wfaces.begin(), fend=wfaces.end(); + f!=fend; + ++f) + { + postProcessSuggestiveContourFace((WXFace*)(*f)); + } +} + +void FEdgeXDetector::postProcessSuggestiveContourFace(WXFace *iFace) { + + // Compute the derivative of the radial curvature in the radial direction, + // at the two extremities of the smooth edge. + // If the derivative is smaller than a given threshold _kr_derivative_epsilon, + // discard the edge. + + // Find the suggestive contour layer of the face (zero or one edge). + vector<WXFaceLayer*> sc_layers; + iFace->retrieveSmoothEdgesLayers(Nature::SUGGESTIVE_CONTOUR, sc_layers); + if(sc_layers.empty()) + return; + + WXFaceLayer *sc_layer; + sc_layer = sc_layers[0]; + + // Compute the derivative value at each vertex of the face, and add it in a vector. + vector<real> kr_derivatives; + + unsigned vertices_nb = iFace->numberOfVertices(); + WXVertex *v, *opposite_vertex_a, *opposite_vertex_b; + WXFace *wxf; + WOEdge *opposite_edge; + Vec3r opposite_edge_vec, normal_vec, radial_normal_vec, er_vec, v_vec, inter, inter1, inter2, tmp_vec; + GeomUtils::intersection_test res; + real kr(0), kr1(0), kr2(0), t; + + for (unsigned i = 0; i < vertices_nb; ++i) { + v = (WXVertex*)(iFace->GetVertex(i)); + + // v is a singular vertex, skip it. + if (v->isBoundary()) { + kr_derivatives.push_back(0); + continue; + } + + v_vec = v->GetVertex(); + er_vec = v->curvatures()->er; + + // For each vertex, iterate on its adjacent faces. + for (WVertex::face_iterator fit = v->faces_begin(), fitend = v->faces_end(); + fit != fitend; + ++fit) { + wxf = dynamic_cast<WXFace*>(*fit); + if(!(wxf->getOppositeEdge(v, opposite_edge))) + continue; + + opposite_vertex_a = (WXVertex*)opposite_edge->GetaVertex(); + opposite_vertex_b = (WXVertex*)opposite_edge->GetbVertex(); + opposite_edge_vec = opposite_vertex_b->GetVertex() - opposite_vertex_a->GetVertex(); + normal_vec = wxf->GetVertexNormal(v); // FIXME: what about e1 ^ e2 ? + radial_normal_vec = er_vec ^ normal_vec; + + // Test wether the radial plan intersects with the edge at the opposite of v. + res = GeomUtils::intersectRayPlane(opposite_vertex_a->GetVertex(), opposite_edge_vec, + radial_normal_vec, -(v_vec * radial_normal_vec), + t, + 1.e-06); + + // If there is an intersection, compute the value of the derivative ath that point. + if ((res == GeomUtils::DO_INTERSECT) && (t >= 0) && (t <= 1)) { + kr = t * opposite_vertex_a->curvatures()->Kr + (1 - t) * opposite_vertex_b->curvatures()->Kr; + inter = opposite_vertex_a->GetVertex() + t * opposite_edge_vec; + tmp_vec = inter - v->GetVertex(); + // Is it kr1 or kr2? + if (tmp_vec * er_vec > 0) { + kr2 = kr; + inter2 = inter; + } else { + kr1 = kr; + inter1 = inter; + } + } + } + + // Now we have kr1 and kr2 along the radial direction, for one vertex of iFace. + // We have to compute the derivative of kr for that vertex, equal to: + // (kr2 - kr1) / dist(inter1, inter2). + // Then we add it to the vector of derivatives. + v->curvatures()->dKr = (kr2 - kr1) / (inter2 - inter1).norm(); + kr_derivatives.push_back(v->curvatures()->dKr); + } + + // At that point, we have the derivatives for each vertex of iFace. + // All we have to do now is to use linear interpolation to compute the values at + // the extremities of the smooth edge. + WXSmoothEdge *sc_edge = sc_layer->getSmoothEdge(); + WOEdge *sc_oedge = sc_edge->woea(); + t = sc_edge->ta(); + if (t * kr_derivatives[iFace->GetIndex(sc_oedge->GetaVertex())] + + (1 - t) * kr_derivatives[iFace->GetIndex(sc_oedge->GetbVertex())] < _kr_derivative_epsilon) { + sc_layer->removeSmoothEdge(); + return; + } + sc_oedge = sc_edge->woeb(); + t = sc_edge->tb(); + if (t * kr_derivatives[iFace->GetIndex(sc_oedge->GetaVertex())] + + (1 - t) * kr_derivatives[iFace->GetIndex(sc_oedge->GetbVertex())] < _kr_derivative_epsilon) + sc_layer->removeSmoothEdge(); +} + + +// Build Smooth edges +///////////////////// +void FEdgeXDetector::buildSmoothEdges(WXShape* iShape){ + // Make a last pass to build smooth edges from the previous stored values: + //-------------------------------------------------------------------------- + vector<WFace*>& wfaces = iShape->GetFaceList(); + for(vector<WFace*>::iterator f=wfaces.begin(), fend=wfaces.end(); + f!=fend; + ++f) + { + vector<WXFaceLayer*>& faceLayers = ((WXFace*)(*f))->getSmoothLayers(); + for(vector<WXFaceLayer*>::iterator wxfl = faceLayers.begin(), wxflend=faceLayers.end(); + wxfl!=wxflend; + ++wxfl){ + (*wxfl)->BuildSmoothEdge(); + } + } +} diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.h b/source/blender/freestyle/intern/view_map/FEdgeXDetector.h new file mode 100755 index 00000000000..28034f3f42b --- /dev/null +++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.h @@ -0,0 +1,153 @@ +// +// Filename : FEdgeXDetector.h +// Author(s) : Stephane Grabli +// Purpose : Detects/flags/builds extended features edges on the +// WXEdge structure +// Date of creation : 26/10/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + + +#ifndef FEDGEXDETECTOR_H +# define FEDGEXDETECTOR_H + +# include <vector> +# include "../system/FreestyleConfig.h" +# include "../geometry/Geom.h" +# include "../winged_edge/WXEdge.h" +# include "../winged_edge/Curvature.h" +# include "../system/ProgressBar.h" + +using namespace Geometry; + +/*! This class takes as input a WXEdge structure and fills it + */ + +class LIB_VIEW_MAP_EXPORT FEdgeXDetector +{ +public: + + FEdgeXDetector() { + _pProgressBar = 0; + _computeViewIndependant = true; + _bbox_diagonal = 1.0; + _meanEdgeSize = 0; + _computeRidgesAndValleys = true; + _computeSuggestiveContours = true; + _sphereRadius = 1.0; + _orthographicProjection = false; + _changes = false; + _kr_derivative_epsilon = 0.0; + } + virtual ~FEdgeXDetector() {} + + /*! Process shapes from a WingedEdge containing a list of WShapes */ + virtual void processShapes(WingedEdge&); + + // GENERAL STUFF + virtual void preProcessShape(WXShape* iShape); + virtual void preProcessFace(WXFace* iFace); + virtual void computeCurvatures(WXVertex *iVertex); + + // SILHOUETTE + virtual void processSilhouetteShape(WXShape* iShape); + virtual void ProcessSilhouetteFace(WXFace *iFace); + virtual void ProcessSilhouetteEdge(WXEdge *iEdge); + + // CREASE + virtual void processCreaseShape(WXShape* iShape); + virtual void ProcessCreaseEdge(WXEdge *iEdge); + + // BORDER + virtual void processBorderShape(WXShape* iShape); + virtual void ProcessBorderEdge(WXEdge *iEdge); + + // RIDGES AND VALLEYS + virtual void processRidgesAndValleysShape(WXShape* iShape); + virtual void ProcessRidgeFace(WXFace *iFace); + + // SUGGESTIVE CONTOURS + virtual void processSuggestiveContourShape(WXShape* iShape); + virtual void ProcessSuggestiveContourFace(WXFace *iFace); + virtual void postProcessSuggestiveContourShape(WXShape* iShape); + virtual void postProcessSuggestiveContourFace(WXFace *iFace); + /*! Sets the minimal derivative of the radial curvature for suggestive contours + * \param dkr + * The minimal derivative of the radial curvature + */ + inline void setSuggestiveContourKrDerivativeEpsilon(real dkr) { + if (dkr != _kr_derivative_epsilon){ + _kr_derivative_epsilon = dkr; + _changes = true; + } + } + + // EVERYBODY + virtual void buildSmoothEdges(WXShape* iShape); + + /*! Sets the current viewpoint */ + inline void setViewpoint(const Vec3r& ivp) {_Viewpoint = ivp;} + inline void enableOrthographicProjection(bool b) {_orthographicProjection = b;} + inline void enableRidgesAndValleysFlag(bool b) {_computeRidgesAndValleys = b;} + inline void enableSuggestiveContours(bool b) {_computeSuggestiveContours = b;} + /*! Sets the radius of the geodesic sphere around each vertex (for the curvature computation) + * \param r + * The radius of the sphere expressed as a ratio of the mean edge size + */ + inline void setSphereRadius(real r) { + if(r!=_sphereRadius){ + _sphereRadius = r; + _changes=true; + } + } + + inline void setProgressBar(ProgressBar *iProgressBar) {_pProgressBar = iProgressBar;} + +protected: + + Vec3r _Viewpoint; + real _bbox_diagonal; // diagonal of the current processed shape bbox + //oldtmp values + bool _computeViewIndependant; + real _meanK1; + real _meanKr; + real _minK1; + real _minKr; + real _maxK1; + real _maxKr; + unsigned _nPoints; + real _meanEdgeSize; + bool _orthographicProjection; + + bool _computeRidgesAndValleys; + bool _computeSuggestiveContours; + real _sphereRadius; // expressed as a ratio of the mean edge size + bool _changes; + + real _kr_derivative_epsilon; + + ProgressBar *_pProgressBar; +}; + +#endif // FEDGEDXETECTOR_H diff --git a/source/blender/freestyle/intern/view_map/Functions0D.cpp b/source/blender/freestyle/intern/view_map/Functions0D.cpp new file mode 100755 index 00000000000..b28ac575d00 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/Functions0D.cpp @@ -0,0 +1,365 @@ + +// +// 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 "Functions0D.h" +# include "ViewMap.h" + +using namespace std; + +namespace Functions0D { + + // Internal function + FEdge* getFEdge(Interface0D& it1, Interface0D& it2){ + return it1.getFEdge(it2); + } + + void getFEdges(Interface0DIterator& it, + FEdge*& fe1, + FEdge*& fe2) { + // count number of vertices + Interface0DIterator prev = it, next = it; + ++next; + int count = 1; + while((!prev.isBegin()) && (count < 3)) + { + --prev; + ++count; + } + while((!next.isEnd()) && (count < 3)) + { + ++next; + ++count; + } + if(count < 3) + { + // if we only have 2 vertices + FEdge * fe = 0; + Interface0DIterator tmp = it; + if(it.isBegin()) + { + ++tmp; + fe = it->getFEdge(*tmp); + } + else + { + --tmp; + fe = it->getFEdge(*tmp); + } + fe1 = fe; + fe2 = 0; + } + else + { + // we have more than 2 vertices + bool begin=false,last=false; + Interface0DIterator previous = it; + if(!previous.isBegin()) + --previous; + else + begin=true; + Interface0DIterator next = it; + ++next; + if(next.isEnd()) + last = true; + if(begin) + { + fe1 = it->getFEdge(*next); + fe2 = 0; + } + else if(last) + { + fe1 = previous->getFEdge(*it); + fe2 = 0; + } + else + { + fe1 = previous->getFEdge(*it); + fe2 = it->getFEdge(*next); + } + } + } + + void getViewEdges(Interface0DIterator &it, + ViewEdge *&ve1, + ViewEdge *&ve2) + { + FEdge * fe1, *fe2; + getFEdges(it, fe1, fe2); + ve1 = fe1->viewedge(); + if(fe2 != 0) + { + ve2 = fe2->viewedge(); + if(ve2 == ve1) + ve2 = 0; + } + else + ve2 = 0; + } + + ViewShape* getShapeF0D(Interface0DIterator& it) + { + ViewEdge *ve1, *ve2; + getViewEdges(it, ve1, ve2); + return ve1->viewShape(); + } + + void getOccludersF0D(Interface0DIterator& it, set<ViewShape*>& oOccluders){ + ViewEdge * ve1, *ve2; + getViewEdges(it, ve1, ve2); + occluder_container::const_iterator oit = ve1->occluders_begin(); + occluder_container::const_iterator oitend = ve1->occluders_end(); + + for(;oit!=oitend; ++oit) + oOccluders.insert((*oit)); + + if(ve2!=0){ + oit = ve2->occluders_begin(); + oitend = ve2->occluders_end(); + for(;oit!=oitend; ++oit) + oOccluders.insert((*oit)); + } + } + + ViewShape * getOccludeeF0D(Interface0DIterator& it){ + ViewEdge * ve1, *ve2; + getViewEdges(it, ve1, ve2); + ViewShape *aShape = ve1->aShape(); + return aShape; + } + + // + int VertexOrientation2DF0D::operator()(Interface0DIterator& iter) { + Vec2f A,C; + Vec2f B(iter->getProjectedX(), iter->getProjectedY()); + if(iter.isBegin()) + A = Vec2f(iter->getProjectedX(), iter->getProjectedY()); + else + { + Interface0DIterator previous = iter; + --previous ; + A = Vec2f(previous->getProjectedX(), previous->getProjectedY()); + } + Interface0DIterator next = iter; + ++next ; + if(next.isEnd()) + C = Vec2f(iter->getProjectedX(), iter->getProjectedY()); + else + C = Vec2f(next->getProjectedX(), next->getProjectedY()); + + Vec2f AB(B-A); + if(AB.norm() != 0) + AB.normalize(); + Vec2f BC(C-B); + if(BC.norm() != 0) + BC.normalize(); + result = AB + BC; + if(result.norm() != 0) + result.normalize(); + return 0; + } + + int VertexOrientation3DF0D::operator()(Interface0DIterator& iter) { + Vec3r A,C; + Vec3r B(iter->getX(), iter->getY(), iter->getZ()); + if(iter.isBegin()) + A = Vec3r(iter->getX(), iter->getY(), iter->getZ()); + else + { + Interface0DIterator previous = iter; + --previous ; + A = Vec3r(previous->getX(), previous->getY(), previous->getZ()); + } + Interface0DIterator next = iter; + ++next ; + if(next.isEnd()) + C = Vec3r(iter->getX(), iter->getY(), iter->getZ()); + else + C = Vec3r(next->getX(), next->getY(), next->getZ()); + + Vec3r AB(B-A); + if(AB.norm() != 0) + AB.normalize(); + Vec3r BC(C-B); + if(BC.norm() != 0) + BC.normalize(); + result = AB + BC; + if(result.norm() != 0) + result.normalize(); + return 0; + } + + int Curvature2DAngleF0D::operator()(Interface0DIterator& iter) { + Interface0DIterator tmp1 = iter, tmp2 = iter; + ++tmp2; + unsigned count = 1; + while((!tmp1.isBegin()) && (count < 3)) + { + --tmp1; + ++count; + } + while((!tmp2.isEnd()) && (count < 3)) + { + ++tmp2; + ++count; + } + if(count < 3) { + // if we only have 2 vertices + result = 0; + return 0; + } + + Interface0DIterator v = iter; + if(iter.isBegin()) + ++v; + Interface0DIterator next=v; + ++next; + if(next.isEnd()) + { + next = v; + --v; + } + Interface0DIterator prev=v; + --prev; + + Vec2r A(prev->getProjectedX(), prev->getProjectedY()); + Vec2r B(v->getProjectedX(), v->getProjectedY()); + Vec2r C(next->getProjectedX(), next->getProjectedY()); + Vec2r AB(B-A); + Vec2r BC(C-B); + Vec2r N1(-AB[1], AB[0]); + if(N1.norm() != 0) + N1.normalize(); + Vec2r N2(-BC[1], BC[0]); + if(N2.norm() != 0) + N2.normalize(); + if((N1.norm() == 0) && (N2.norm() == 0)) + { + Exception::raiseException(); + result = 0; + return -1; + } + double cosin = N1*N2; + if(cosin > 1) + cosin = 1; + if(cosin < -1) + cosin = -1; + result = acos(cosin); + return 0; + } + + int ZDiscontinuityF0D::operator()(Interface0DIterator& iter) { + FEdge *fe1, *fe2; + getFEdges(iter, fe1, fe2); + result = fe1->z_discontinuity(); + if(fe2!=0){ + result += fe2->z_discontinuity(); + result /= 2.f; + } + return 0; + } + + int Normal2DF0D::operator()(Interface0DIterator& iter) { + FEdge *fe1, *fe2; + getFEdges(iter,fe1,fe2); + Vec3f e1(fe1->orientation2d()); + Vec2f n1(e1[1], -e1[0]); + Vec2f n(n1); + if(fe2 != 0) + { + Vec3f e2(fe2->orientation2d()); + Vec2f n2(e2[1], -e2[0]); + n += n2; + } + n.normalize(); + result = n; + return 0; + } + + int MaterialF0D::operator()(Interface0DIterator& iter) { + FEdge *fe1, *fe2; + getFEdges(iter,fe1,fe2); + + if(fe1 == 0) + getFEdges(iter, fe1, fe2); + if(fe1->isSmooth()) + result = ((FEdgeSmooth*)fe1)->frs_material(); + else + result = ((FEdgeSharp*)fe1)->bFrsMaterial(); + // const SShape * sshape = getShapeF0D(iter); + // return sshape->material(); + return 0; + } + + int ShapeIdF0D::operator()(Interface0DIterator& iter) { + ViewShape * vshape = getShapeF0D(iter); + result = vshape->getId(); + return 0; + } + + int QuantitativeInvisibilityF0D::operator()(Interface0DIterator& iter) { + ViewEdge * ve1, *ve2; + getViewEdges(iter,ve1,ve2); + unsigned int qi1, qi2; + qi1 = ve1->qi(); + if(ve2 != 0){ + qi2 = ve2->qi(); + if(qi2!=qi1) + cout << "QuantitativeInvisibilityF0D: ambiguous evaluation for point " << iter->getId() << endl; + } + result = qi1; + return 0; + } + + int CurveNatureF0D::operator()(Interface0DIterator& iter) { + Nature::EdgeNature nat = 0; + ViewEdge * ve1, *ve2; + getViewEdges(iter, ve1, ve2); + nat |= ve1->getNature(); + if(ve2!=0) + nat |= ve2->getNature(); + result = nat; + return 0; + } + + int GetOccludersF0D::operator()(Interface0DIterator& iter) { + set<ViewShape*> occluders; + getOccludersF0D(iter,occluders); + result.clear(); + // vsOccluders.insert(vsOccluders.begin(), occluders.begin(), occluders.end()); + for(set<ViewShape*>::iterator it=occluders.begin(), itend=occluders.end(); + it!=itend; + ++it){ + result.push_back((*it)); + } + return 0; + } + + int GetShapeF0D::operator()(Interface0DIterator& iter) { + result = getShapeF0D(iter); + return 0; + } + + int GetOccludeeF0D::operator()(Interface0DIterator& iter) { + result = getOccludeeF0D(iter); + return 0; + } + +} // end of namespace Functions0D diff --git a/source/blender/freestyle/intern/view_map/Functions0D.h b/source/blender/freestyle/intern/view_map/Functions0D.h new file mode 100755 index 00000000000..4adbc8a1bf5 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/Functions0D.h @@ -0,0 +1,500 @@ +// +// Filename : Functions0D.h +// Author(s) : Stephane Grabli, Emmanuel Turquin +// Purpose : Functions taking 0D input +// Date of creation : 01/07/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef FUNCTIONS0D_H +# define FUNCTIONS0D_H + +# include "../system/Precision.h" +# include "Interface0D.h" +# include "../geometry/Geom.h" +# include "../system/Exception.h" +# include "../scene_graph/FrsMaterial.h" +# include <set> +# include <vector> +class FEdge; +class ViewEdge; +class SShape; + +using namespace Geometry; + +#include "../python/Director.h" + +// +// UnaryFunction0D (base class for functions in 0D) +// +/////////////////////////////////////////////////////////// + +template <class T> +/*! Base class for Unary Functions (functors) working + * on Interface0DIterator. + * A unary function will be used by calling + * its operator() on an Interface0DIterator. + * \attention In the scripting language, there exists + * several prototypes depending on the returned value type. + * For example, you would inherit from a UnaryFunction0DDouble + * if you wish to define a function that returns a double. + * The different existing prototypes are: + * - UnaryFunction0DVoid + * - UnaryFunction0DUnsigned + * - UnaryFunction0DReal + * - UnaryFunction0DFloat + * - UnaryFunction0DDouble + * - UnaryFunction0DVec2f + * - UnaryFunction0DVec3f + */ +class /*LIB_VIEW_MAP_EXPORT*/ UnaryFunction0D +{ +public: + + T result; + PyObject *py_uf0D; + + /*! The type of the value + * returned by the functor. + */ + typedef T ReturnedValueType; + /*! Default constructor. */ +UnaryFunction0D() { py_uf0D = 0;} + /*! Destructor; */ + virtual ~UnaryFunction0D() {} + /*! Returns the string "UnaryFunction0D" */ + virtual string getName() const { + return "UnaryFunction0D"; + } + /*! The operator (). + * \param iter + * An Interface0DIterator pointing onto + * the point at which we wish to evaluate + * the function. + * \return the result of the function of type T. + */ + virtual int operator()(Interface0DIterator& iter) { + return Director_BPy_UnaryFunction0D___call__( this, py_uf0D, iter ); + } + +}; + +# ifdef SWIG +%feature("director") UnaryFunction0D<void>; +%feature("director") UnaryFunction0D<unsigned>; +%feature("director") UnaryFunction0D<float>; +%feature("director") UnaryFunction0D<double>; +%feature("director") UnaryFunction0D<Vec2f>; +%feature("director") UnaryFunction0D<Vec3f>; +%feature("director") UnaryFunction0D<Id>; + +%template(UnaryFunction0DVoid) UnaryFunction0D<void>; +%template(UnaryFunction0DUnsigned) UnaryFunction0D<unsigned>; +%template(UnaryFunction0DFloat) UnaryFunction0D<float>; +%template(UnaryFunction0DDouble) UnaryFunction0D<double>; +%template(UnaryFunction0DVec2f) UnaryFunction0D<Vec2f>; +%template(UnaryFunction0DVec3f) UnaryFunction0D<Vec3f>; +%template(UnaryFunction0DId) UnaryFunction0D<Id>; +%template(UnaryFunction0DViewShape) UnaryFunction0D<ViewShape*>; +%template(UnaryFunction0DVectorViewShape) UnaryFunction0D<std::vector<ViewShape*> >; +# endif // SWIG + + +// +// Functions definitions +// +/////////////////////////////////////////////////////////// +class ViewShape; +namespace Functions0D { + + // GetXF0D + /*! Returns the X 3D coordinate of an Interface0D. */ + class LIB_VIEW_MAP_EXPORT GetXF0D : public UnaryFunction0D<real> + { + public: + /*! Returns the string "GetXF0D"*/ + string getName() const { + return "GetXF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter) { + result = iter->getX(); + return 0; + } + }; + + // GetYF0D + /*! Returns the Y 3D coordinate of an Interface0D. */ + class LIB_VIEW_MAP_EXPORT GetYF0D : public UnaryFunction0D<real> + { + public: + /*! Returns the string "GetYF0D"*/ + string getName() const { + return "GetYF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter) { + result = iter->getY(); + return 0; + } + }; + + // GetZF0D + /*! Returns the Z 3D coordinate of an Interface0D. */ + class LIB_VIEW_MAP_EXPORT GetZF0D : public UnaryFunction0D<real> + { + public: + /*! Returns the string "GetZF0D"*/ + string getName() const { + return "GetZF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter) { + result = iter->getZ(); + return 0; + } + }; + + // GetProjectedXF0D + /*! Returns the X 3D projected coordinate of an Interface0D. */ + class LIB_VIEW_MAP_EXPORT GetProjectedXF0D : public UnaryFunction0D<real> + { + public: + /*! Returns the string "GetProjectedXF0D"*/ + string getName() const { + return "GetProjectedXF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter) { + result = iter->getProjectedX(); + return 0; + } + }; + + // GetProjectedYF0D + /*! Returns the Y projected 3D coordinate of an Interface0D. */ + class LIB_VIEW_MAP_EXPORT GetProjectedYF0D : public UnaryFunction0D<real> + { + public: + /*! Returns the string "GetProjectedYF0D"*/ + string getName() const { + return "GetProjectedYF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter) { + result = iter->getProjectedY(); + return 0; + } + }; + + // GetProjectedZF0D + /*! Returns the Z projected 3D coordinate of an Interface0D. */ + class LIB_VIEW_MAP_EXPORT GetProjectedZF0D : public UnaryFunction0D<real> + { + public: + /*! Returns the string "GetProjectedZF0D"*/ + string getName() const { + return "GetProjectedZF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter) { + result = iter->getProjectedZ(); + return 0; + } + }; + + // GetCurvilinearAbscissaF0D + /*! Returns the curvilinear abscissa of an Interface0D in the context of its 1D element. */ + class LIB_VIEW_MAP_EXPORT GetCurvilinearAbscissaF0D : public UnaryFunction0D<float> + { + public: + /*! Returns the string "GetCurvilinearAbscissaF0D"*/ + string getName() const { + return "GetCurvilinearAbscissaF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter) { + result = iter.t(); + return 0; + } + }; + + // GetParameterF0D + /*! Returns the parameter of an Interface0D in the context of its 1D element. */ + class LIB_VIEW_MAP_EXPORT GetParameterF0D : public UnaryFunction0D<float> + { + public: + /*! Returns the string "GetCurvilinearAbscissaF0D"*/ + string getName() const { + return "GetParameterF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter) { + result = iter.u(); + return 0; + } + }; + + // VertexOrientation2DF0D + /*! Returns a Vec2r giving the 2D oriented tangent to the 1D element + * to which the Interface0DIterator& belongs to and + * evaluated at the Interface0D pointed by this Interface0DIterator&. + */ + class LIB_VIEW_MAP_EXPORT VertexOrientation2DF0D : public UnaryFunction0D<Vec2f> + { + public: + /*! Returns the string "VertexOrientation2DF0D"*/ + string getName() const { + return "VertexOrientation2DF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // VertexOrientation3DF0D + /*! Returns a Vec3r giving the 3D oriented tangent to the 1D element + * to which the Interface0DIterator& belongs to and + * evaluated at the Interface0D pointed by this Interface0DIterator&. + */ + class LIB_VIEW_MAP_EXPORT VertexOrientation3DF0D : public UnaryFunction0D<Vec3f> + { + public: + /*! Returns the string "VertexOrientation3DF0D"*/ + string getName() const { + return "VertexOrientation3DF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // Curvature2DAngleF0D + /*! Returns a real giving the 2D curvature (as an angle) of the 1D element + * to which the Interface0DIterator& belongs to and + * evaluated at the Interface0D pointed by this Interface0DIterator&. + */ + class LIB_VIEW_MAP_EXPORT Curvature2DAngleF0D : public UnaryFunction0D<real> + { + public: + /*! Returns the string "Curvature2DAngleF0D"*/ + string getName() const { + return "Curvature2DAngleF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // ZDiscontinuity + /*! Returns a real giving the distance between + * and Interface0D and the shape that lies behind (occludee). + * This distance is evaluated in the camera space and normalized + * between 0 and 1. Therefore, if no oject is occluded by the + * shape to which the Interface0D belongs to, 1 is returned. + */ + class LIB_VIEW_MAP_EXPORT ZDiscontinuityF0D : public UnaryFunction0D<real> + { + public: + /*! Returns the string "ZDiscontinuityF0D"*/ + string getName() const { + return "ZDiscontinuityF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // Normal2DF0D + /*! Returns a Vec2f giving the normalized 2D normal to the 1D element + * to which the Interface0DIterator& belongs to and + * evaluated at the Interface0D pointed by this Interface0DIterator&. + */ + class LIB_VIEW_MAP_EXPORT Normal2DF0D : public UnaryFunction0D<Vec2f> + { + public: + /*! Returns the string "Normal2DF0D"*/ + string getName() const { + return "Normal2DF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // MaterialF0D + /*! Returns the material of the object evaluated at the Interface0D. + * This evaluation can be ambiguous (in the case of a TVertex for example. + * This functor tries to remove this ambiguity using the context + * offered by the 1D element to which the Interface0DIterator& belongs + * to and by arbitrary chosing the material of the face + * that lies on its left when following the 1D element if there + * are two different materials on each side of the point. + * However, there still can be problematic cases, and the user willing + * to deal with this cases in a specific way should implement + * its own getMaterial functor. + */ + class LIB_VIEW_MAP_EXPORT MaterialF0D : public UnaryFunction0D<FrsMaterial> + { + public: + /*! Returns the string "MaterialF0D"*/ + string getName() const { + return "MaterialF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // ShapeIdF0D + /*! Returns the Id of the Shape the Interface0D belongs to. + * This evaluation can be ambiguous (in the case of a TVertex for example). + * This functor tries to remove this ambiguity using the context + * offered by the 1D element to which the Interface0DIterator& belongs + * to. + * However, there still can be problematic cases, and the user willing + * to deal with this cases in a specific way should implement + * its own getShapeIdF0D functor. + */ + class LIB_VIEW_MAP_EXPORT ShapeIdF0D : public UnaryFunction0D<Id> + { + public: + /*! Returns the string "ShapeIdF0D"*/ + string getName() const { + return "ShapeIdF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // QiF0D + /*! Returns the quantitative invisibility of this Interface0D. + * This evaluation can be ambiguous (in the case of a TVertex for example). + * This functor tries to remove this ambiguity using the context + * offered by the 1D element to which the Interface0DIterator& belongs + * to. + * However, there still can be problematic cases, and the user willing + * to deal with this cases in a specific way should implement + * its own getQIF0D functor. + */ + class LIB_VIEW_MAP_EXPORT QuantitativeInvisibilityF0D : public UnaryFunction0D<unsigned int> + { + public: + /*! Returns the string "QuantitativeInvisibilityF0D"*/ + string getName() const { + return "QuantitativeInvisibilityF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // CurveNatureF0D + /*! Returns the Nature::EdgeNature of the 1D element the + * Interface0DIterator& belongs to. + */ + class LIB_VIEW_MAP_EXPORT CurveNatureF0D : public UnaryFunction0D<Nature::EdgeNature> + { + public: + /*! Returns the string "QuantitativeInvisibilityF0D"*/ + string getName() const { + return "CurveNatureF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // GetShapeF0D + /*! Returns the ViewShape* + * containing the Interface0D + */ + class LIB_VIEW_MAP_EXPORT GetShapeF0D : public UnaryFunction0D< ViewShape*> + { + public: + /*! Returns the string "GetShapeF0D"*/ + string getName() const { + return "GetShapeF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // GetOccludersF0D + /*! Returns a vector containing the ViewShape* + * occluding the Interface0D + */ + class LIB_VIEW_MAP_EXPORT GetOccludersF0D : public UnaryFunction0D< std::vector<ViewShape*> > + { + public: + /*! Returns the string "GetOccludersF0D"*/ + string getName() const { + return "GetOccludersF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + // GetOccludeeF0D + /*! Returns the ViewShape* + * "occluded" by the Interface0D + */ + class LIB_VIEW_MAP_EXPORT GetOccludeeF0D: public UnaryFunction0D< ViewShape*> + { + public: + /*! Returns the string "GetOccludeeF0D"*/ + string getName() const { + return "GetOccludeeF0D"; + } + /*! the () operator.*/ + int operator()(Interface0DIterator& iter); + }; + + + + /////////////////////////// Internal //////////////////////////// + + // getFEdge + LIB_VIEW_MAP_EXPORT + FEdge* getFEdge(Interface0D& it1, Interface0D& it2); + + // getFEdges + LIB_VIEW_MAP_EXPORT + void getFEdges(Interface0DIterator& it, + FEdge*& fe1, + FEdge*& fe2); + + // getViewEdges + LIB_VIEW_MAP_EXPORT + void getViewEdges(Interface0DIterator& it, + ViewEdge *&ve1, + ViewEdge *&ve2); + + // getShapeF0D + LIB_VIEW_MAP_EXPORT + ViewShape* getShapeF0D(Interface0DIterator& it); + + // getOccludersF0D + LIB_VIEW_MAP_EXPORT + void getOccludersF0D(Interface0DIterator& it, std::set<ViewShape*>& oOccluders); + + // getOccludeeF0D + LIB_VIEW_MAP_EXPORT + ViewShape* getOccludeeF0D(Interface0DIterator& it); + +} // end of namespace Functions0D + +#endif // FUNCTIONS0D_H diff --git a/source/blender/freestyle/intern/view_map/Functions1D.cpp b/source/blender/freestyle/intern/view_map/Functions1D.cpp new file mode 100755 index 00000000000..8545c660084 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/Functions1D.cpp @@ -0,0 +1,231 @@ + +// +// 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 "Functions1D.h" +using namespace std; + +namespace Functions1D { + + int GetXF1D::operator()(Interface1D& inter) { + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + + int GetYF1D::operator()(Interface1D& inter) { + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + + int GetZF1D::operator()(Interface1D& inter) { + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + + int GetProjectedXF1D::operator()(Interface1D& inter) { + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + + int GetProjectedYF1D::operator()(Interface1D& inter) { + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + + int GetProjectedZF1D::operator()(Interface1D& inter) { + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + + int Orientation2DF1D::operator()(Interface1D& inter) { + FEdge * fe = dynamic_cast<FEdge*>(&inter); + if(fe){ + Vec3r res = fe->orientation2d(); + result = Vec2f(res[0], res[1]); + } else { + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + } + return 0; + } + + int Orientation3DF1D::operator()(Interface1D& inter) { + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + + int ZDiscontinuityF1D::operator()(Interface1D& inter) { + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + + int QuantitativeInvisibilityF1D::operator()(Interface1D& inter) { + ViewEdge* ve = dynamic_cast<ViewEdge*>(&inter); + if (ve) { + result = ve->qi(); + return 0; + } + FEdge *fe = dynamic_cast<FEdge*>(&inter); + if (fe) { + result = ve->qi(); + return 0; + } + result = integrate(_func, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + + int CurveNatureF1D::operator()(Interface1D& inter) { + ViewEdge* ve = dynamic_cast<ViewEdge*>(&inter); + if (ve) + result = ve->getNature(); + else{ + // we return a nature that contains every + // natures of the viewedges spanned by the chain. + Nature::EdgeNature nat = Nature::NO_FEATURE; + Interface0DIterator it = inter.verticesBegin(); + while(!it.isEnd()){ + nat |= _func(it); + ++it; + } + result = nat; + } + return 0; + } + + int TimeStampF1D::operator()(Interface1D& inter) { + TimeStamp *timestamp = TimeStamp::instance(); + inter.setTimeStamp(timestamp->getTimeStamp()); + return 0; + } + + int ChainingTimeStampF1D::operator()(Interface1D& inter) { + TimeStamp *timestamp = TimeStamp::instance(); + ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter); + if(ve) + ve->setChainingTimeStamp(timestamp->getTimeStamp()); + return 0; + } + + int IncrementChainingTimeStampF1D::operator()(Interface1D& inter) { + ViewEdge *ve = dynamic_cast<ViewEdge*>(&inter); + if(ve) + ve->setChainingTimeStamp(ve->getChainingTimeStamp()+1); + return 0; + } + + int GetShapeF1D::operator()(Interface1D& inter) { + vector<ViewShape*> shapesVector; + set<ViewShape*> shapesSet; + ViewEdge* ve = dynamic_cast<ViewEdge*>(&inter); + if (ve){ + shapesVector.push_back(ve->viewShape()); + }else{ + Interface0DIterator it=inter.verticesBegin(), itend=inter.verticesEnd(); + for(;it!=itend;++it) + shapesSet.insert(Functions0D::getShapeF0D(it)); + shapesVector.insert<set<ViewShape*>::iterator>(shapesVector.begin(), shapesSet.begin(), shapesSet.end()); + } + result = shapesVector; + return 0; + } + + int GetOccludersF1D::operator()(Interface1D& inter) { + vector<ViewShape*> shapesVector; + set<ViewShape*> shapesSet; + ViewEdge* ve = dynamic_cast<ViewEdge*>(&inter); + if (ve){ + result = ve->occluders(); + }else{ + Interface0DIterator it=inter.verticesBegin(), itend=inter.verticesEnd(); + for(;it!=itend;++it){ + Functions0D::getOccludersF0D(it, shapesSet); + } + shapesVector.insert(shapesVector.begin(), shapesSet.begin(), shapesSet.end()); + result = shapesVector; + } + return 0; + } + + int GetOccludeeF1D::operator()(Interface1D& inter) { + vector<ViewShape*> shapesVector; + set<ViewShape*> shapesSet; + ViewEdge* ve = dynamic_cast<ViewEdge*>(&inter); + if (ve){ + ViewShape * aShape = ve->aShape(); + shapesVector.push_back(aShape); + }else{ + Interface0DIterator it=inter.verticesBegin(), itend=inter.verticesEnd(); + for(;it!=itend;++it){ + shapesSet.insert(Functions0D::getOccludeeF0D(it)); + } + shapesVector.insert<set<ViewShape*>::iterator>(shapesVector.begin(), shapesSet.begin(), shapesSet.end()); + } + result = shapesVector; + return 0; + } + // Internal + //////////// + + void getOccludeeF1D(Interface1D& inter, set<ViewShape*>& oShapes){ + ViewEdge* ve = dynamic_cast<ViewEdge*>(&inter); + if (ve){ + ViewShape * aShape = ve->aShape(); + if(aShape == 0){ + oShapes.insert(0); + return; + } + oShapes.insert(aShape); + } + else{ + Interface0DIterator it=inter.verticesBegin(), itend=inter.verticesEnd(); + for(;it!=itend;++it) + oShapes.insert(Functions0D::getOccludeeF0D(it)); + } + } + + void getOccludersF1D(Interface1D& inter, set<ViewShape*>& oShapes){ + ViewEdge* ve = dynamic_cast<ViewEdge*>(&inter); + if (ve){ + vector<ViewShape*>& occluders = ve->occluders(); + oShapes.insert<vector<ViewShape*>::iterator>(occluders.begin(), occluders.end()); + } + else{ + Interface0DIterator it=inter.verticesBegin(), itend=inter.verticesEnd(); + for(;it!=itend;++it){ + set<ViewShape*> shapes; + Functions0D::getOccludersF0D(it, shapes); + for(set<ViewShape*>::iterator s=shapes.begin(), send=shapes.end(); + s!=send; + ++s) + oShapes.insert(*s); + } + } + } + + void getShapeF1D(Interface1D& inter, set<ViewShape*>& oShapes){ + ViewEdge* ve = dynamic_cast<ViewEdge*>(&inter); + if (ve){ + oShapes.insert(ve->viewShape()); + }else{ + Interface0DIterator it=inter.verticesBegin(), itend=inter.verticesEnd(); + for(;it!=itend;++it) + oShapes.insert(Functions0D::getShapeF0D(it)); + } + } +} // end of namespace Functions1D diff --git a/source/blender/freestyle/intern/view_map/Functions1D.h b/source/blender/freestyle/intern/view_map/Functions1D.h new file mode 100755 index 00000000000..ba42b25b47e --- /dev/null +++ b/source/blender/freestyle/intern/view_map/Functions1D.h @@ -0,0 +1,555 @@ +// +// Filename : Functions1D.h +// Author(s) : Stephane Grabli, Emmanuel Turquin +// Purpose : Functions taking 1D input +// Date of creation : 01/07/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef FUNCTIONS1D_HPP +# define FUNCTIONS1D_HPP + +# include "ViewMap.h" +# include "Functions0D.h" +# include "Interface1D.h" +# include "../system/Precision.h" +# include "../system/TimeStamp.h" +# include "../system/FreestyleConfig.h" + +#include "../python/Director.h" + +// +// UnaryFunction1D (base class for functions in 1D) +// +/////////////////////////////////////////////////////////// + +/*! Base class for Unary Functions (functors) working + * on Interface1D. + * A unary function will be used by calling + * its operator() on an Interface1D. + * \attention In the scripting language, there exists + * several prototypes depending on the returned value type. + * For example, you would inherit from a UnaryFunction1DDouble + * if you wish to define a function that returns a double. + * The different existing prototypes are: + * - UnaryFunction1DVoid + * - UnaryFunction1DUnsigned + * - UnaryFunction1DReal + * - UnaryFunction1DFloat + * - UnaryFunction1DDouble + * - UnaryFunction1DVec2f + * - UnaryFunction1DVec3f + */ +template <class T> +class /*LIB_VIEW_MAP_EXPORT*/ UnaryFunction1D +{ +public: + + T result; + PyObject *py_uf1D; + + /*! The type of the value + * returned by the functor. + */ + typedef T ReturnedValueType; + + /*! Default constructor */ + UnaryFunction1D(){_integration = MEAN;} + /*! Builds a UnaryFunction1D from an integration type. + * \param iType + * In case the result for the Interface1D would be + * obtained by evaluating a 0D function over the different + * Interface0D of the Interface1D, \a iType tells which + * integration method to use. + * The default integration method is the MEAN. + */ + UnaryFunction1D(IntegrationType iType){_integration = iType;} + /*! destructor. */ + virtual ~UnaryFunction1D() {} + + /*! returns the string "UnaryFunction1D". */ + virtual string getName() const { + return "UnaryFunction1D"; + } + /*! The operator (). + * \param inter + * The Interface1D on which we wish to evaluate + * the function. + * \return the result of the function of type T. + */ + virtual int operator()(Interface1D& inter) { + return Director_BPy_UnaryFunction1D___call__( this, py_uf1D, inter ); + } + + /*! Sets the integration method */ + void setIntegrationType(IntegrationType integration) { + _integration = integration; + } + /*! Returns the integration method. */ + IntegrationType getIntegrationType() const { + return _integration; + } + +protected: + + IntegrationType _integration; +}; + + +class UnaryFunction1D_void +{ +public: + + PyObject *py_uf1D; + + UnaryFunction1D_void(){_integration = MEAN;} + UnaryFunction1D_void(IntegrationType iType){_integration = iType;} + virtual ~UnaryFunction1D_void() {} + + virtual string getName() const { + return "UnaryFunction1D_void"; + } + + int operator()(Interface1D& inter) { + return Director_BPy_UnaryFunction1D___call__( this, py_uf1D, inter ); + } + + void setIntegrationType(IntegrationType integration) { _integration = integration; } + IntegrationType getIntegrationType() const { return _integration; } + + protected: + IntegrationType _integration; +}; + + +// +// Functions definitions +// +/////////////////////////////////////////////////////////// + +namespace Functions1D { + + // GetXF1D + /*! Returns the X 3D coordinate of an Interface1D. */ + class LIB_VIEW_MAP_EXPORT GetXF1D : public UnaryFunction1D<real> + { + private: + Functions0D::GetXF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + GetXF1D(IntegrationType iType) : UnaryFunction1D<real>(iType){} + /*! Returns the string "GetXF1D"*/ + string getName() const { + return "GetXF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter) ; + }; + + // GetYF1D + /*! Returns the Y 3D coordinate of an Interface1D. */ + class LIB_VIEW_MAP_EXPORT GetYF1D : public UnaryFunction1D<real> + { + private: + Functions0D::GetYF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + GetYF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType){} + /*! Returns the string "GetYF1D"*/ + string getName() const { + return "GetYF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter) ; + }; + + // GetZF1D + /*! Returns the Z 3D coordinate of an Interface1D. */ + class LIB_VIEW_MAP_EXPORT GetZF1D : public UnaryFunction1D<real> + { + private: + Functions0D::GetZF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + GetZF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType){} + /*! Returns the string "GetZF1D"*/ + string getName() const { + return "GetZF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter) ; + }; + + // GetProjectedXF1D + /*! Returns the projected X 3D coordinate of an Interface1D. */ + class LIB_VIEW_MAP_EXPORT GetProjectedXF1D : public UnaryFunction1D<real> + { + private: + Functions0D::GetProjectedXF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + GetProjectedXF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType){} + public: + /*! Returns the string "GetProjectedXF1D"*/ + string getName() const { + return "GetProjectedXF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // GetProjectedYF1D + /*! Returns the projected Y 3D coordinate of an Interface1D. */ + class LIB_VIEW_MAP_EXPORT GetProjectedYF1D : public UnaryFunction1D<real> + { + private: + Functions0D::GetProjectedYF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + GetProjectedYF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType){} + public: + /*! Returns the string "GetProjectedYF1D"*/ + string getName() const { + return "GetProjectedYF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // GetProjectedZF1D + /*! Returns the projected Z 3D coordinate of an Interface1D. */ + class LIB_VIEW_MAP_EXPORT GetProjectedZF1D : public UnaryFunction1D<real> + { + private: + Functions0D::GetProjectedZF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + GetProjectedZF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType){} + public: + /*! Returns the string "GetProjectedZF1D"*/ + string getName() const { + return "GetProjectedZF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // Orientation2DF1D + /*! Returns the 2D orientation as a Vec2f*/ + class LIB_VIEW_MAP_EXPORT Orientation2DF1D : public UnaryFunction1D<Vec2f> + { + private: + Functions0D::VertexOrientation2DF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + Orientation2DF1D(IntegrationType iType = MEAN) : UnaryFunction1D<Vec2f>(iType){} + /*! Returns the string "Orientation2DF1D"*/ + string getName() const { + return "Orientation2DF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // Orientation3DF1D + /*! Returns the 3D orientation as a Vec3f. */ + class LIB_VIEW_MAP_EXPORT Orientation3DF1D : public UnaryFunction1D<Vec3f> + { + private: + Functions0D::VertexOrientation3DF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + Orientation3DF1D(IntegrationType iType = MEAN) : UnaryFunction1D<Vec3f>(iType){} + /*! Returns the string "Orientation3DF1D"*/ + string getName() const { + return "Orientation3DF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // ZDiscontinuityF1D + /*! Returns a real giving the distance between + * and Interface1D and the shape that lies behind (occludee). + * This distance is evaluated in the camera space and normalized + * between 0 and 1. Therefore, if no oject is occluded by the + * shape to which the Interface1D belongs to, 1 is returned. + */ + class LIB_VIEW_MAP_EXPORT ZDiscontinuityF1D : public UnaryFunction1D<real> + { + private: + Functions0D::ZDiscontinuityF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + ZDiscontinuityF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType){} + /*! Returns the string "ZDiscontinuityF1D"*/ + string getName() const { + return "ZDiscontinuityF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // QuantitativeInvisibilityF1D + /*! Returns the Quantitative Invisibility of an Interface1D element. + * If the Interface1D is a ViewEdge, then there is no ambiguity + * concerning the result. But, if the Interface1D results of a chaining + * (chain, stroke), then it might be made of several 1D elements + * of different Quantitative Invisibilities. + */ + class LIB_VIEW_MAP_EXPORT QuantitativeInvisibilityF1D : public UnaryFunction1D<unsigned> + { + private: + Functions0D::QuantitativeInvisibilityF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + QuantitativeInvisibilityF1D(IntegrationType iType = MEAN) : UnaryFunction1D<unsigned int>(iType) {} + /*! Returns the string "QuantitativeInvisibilityF1D"*/ + string getName() const { + return "QuantitativeInvisibilityF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // CurveNatureF1D +/*! Returns the nature of the Interface1D (silhouette, ridge, crease...). + * Except if the Interface1D is a ViewEdge, this result might be ambiguous. + * Indeed, the Interface1D might result from the gathering of several 1D elements, + * each one being of a different nature. An integration method, such as + * the MEAN, might give, in this case, irrelevant results. + */ + class LIB_VIEW_MAP_EXPORT CurveNatureF1D : public UnaryFunction1D<Nature::EdgeNature> + { + private: + Functions0D::CurveNatureF0D _func; + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + CurveNatureF1D(IntegrationType iType = MEAN) : UnaryFunction1D<Nature::EdgeNature>(iType) {} + /*! Returns the string "CurveNatureF1D"*/ + string getName() const { + return "CurveNatureF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // TimeStampF1D +/*! Returns the time stamp of the Interface1D. */ + class LIB_VIEW_MAP_EXPORT TimeStampF1D : public UnaryFunction1D_void + { + public: + /*! Returns the string "TimeStampF1D"*/ + string getName() const { + return "TimeStampF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // IncrementChainingTimeStampF1D +/*! Increments the chaining time stamp of the Interface1D. */ + class LIB_VIEW_MAP_EXPORT IncrementChainingTimeStampF1D : public UnaryFunction1D_void + { + public: + /*! Returns the string "IncrementChainingTimeStampF1D"*/ + string getName() const { + return "IncrementChainingTimeStampF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // ChainingTimeStampF1D +/*! Sets the chaining time stamp of the Interface1D. */ + class LIB_VIEW_MAP_EXPORT ChainingTimeStampF1D : public UnaryFunction1D_void + { + public: + /*! Returns the string "ChainingTimeStampF1D"*/ + string getName() const { + return "ChainingTimeStampF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + + // Curvature2DAngleF1D +/*! Returns the 2D curvature as an angle for an Interface1D. */ + class LIB_VIEW_MAP_EXPORT Curvature2DAngleF1D : public UnaryFunction1D<real> + { + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + Curvature2DAngleF1D(IntegrationType iType = MEAN) : UnaryFunction1D<real>(iType) {} + /*! Returns the string "Curvature2DAngleF1D"*/ + string getName() const { + return "Curvature2DAngleF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter) { + result = integrate(_fun, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + private: + Functions0D::Curvature2DAngleF0D _fun; + }; + + // Normal2DF1D + /*! Returns the 2D normal for an interface 1D. */ + class LIB_VIEW_MAP_EXPORT Normal2DF1D : public UnaryFunction1D<Vec2f> + { + public: + /*! Builds the functor. + * \param iType + * The integration method used to compute + * a single value from a set of values. + */ + Normal2DF1D(IntegrationType iType = MEAN) : UnaryFunction1D<Vec2f>(iType) {} + /*! Returns the string "Normal2DF1D"*/ + string getName() const { + return "Normal2DF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter) { + result = integrate(_fun, inter.verticesBegin(), inter.verticesEnd(), _integration); + return 0; + } + private: + Functions0D::Normal2DF0D _fun; + }; + + // GetShapeF1D + /*! Returns list of shapes covered by this Interface1D. */ + class LIB_VIEW_MAP_EXPORT GetShapeF1D : public UnaryFunction1D<std::vector<ViewShape*> > + { + public: + /*! Builds the functor. + */ + GetShapeF1D() : UnaryFunction1D<std::vector<ViewShape*> >() {} + /*! Returns the string "GetShapeF1D"*/ + string getName() const { + return "GetShapeF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // GetOccludersF1D + /*! Returns list of occluding shapes covered by this Interface1D. */ + class LIB_VIEW_MAP_EXPORT GetOccludersF1D : public UnaryFunction1D<std::vector<ViewShape*> > + { + public: + /*! Builds the functor. + */ + GetOccludersF1D() : UnaryFunction1D<std::vector<ViewShape*> >() {} + /*! Returns the string "GetOccludersF1D"*/ + string getName() const { + return "GetOccludersF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // GetOccludeeF1D + /*! Returns list of occluded shapes covered by this Interface1D. */ + class LIB_VIEW_MAP_EXPORT GetOccludeeF1D : public UnaryFunction1D<std::vector<ViewShape*> > + { + public: + /*! Builds the functor. + */ + GetOccludeeF1D() : UnaryFunction1D<std::vector<ViewShape*> >() {} + /*! Returns the string "GetOccludeeF1D"*/ + string getName() const { + return "GetOccludeeF1D"; + } + /*! the () operator.*/ + int operator()(Interface1D& inter); + }; + + // internal + //////////// + + // getOccludeeF1D + LIB_VIEW_MAP_EXPORT + void getOccludeeF1D(Interface1D& inter, set<ViewShape*>& oShapes); + + // getOccludersF1D + LIB_VIEW_MAP_EXPORT + void getOccludersF1D(Interface1D& inter, set<ViewShape*>& oShapes); + + // getShapeF1D + LIB_VIEW_MAP_EXPORT + void getShapeF1D(Interface1D& inter, set<ViewShape*>& oShapes); + +} // end of namespace Functions1D + +#endif // FUNCTIONS1D_HPP diff --git a/source/blender/freestyle/intern/view_map/Interface0D.h b/source/blender/freestyle/intern/view_map/Interface0D.h new file mode 100755 index 00000000000..48d956eec19 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/Interface0D.h @@ -0,0 +1,360 @@ +// +// Filename : Interface0D.h +// Author(s) : Emmanuel Turquin +// Purpose : Interface to 0D elts +// Date of creation : 01/07/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef INTERFACE0D_H +# define INTERFACE0D_H + +# include <Python.h> +# include <string> +# include <iostream> +# include "../system/Id.h" +# include "../system/Precision.h" +# include "../winged_edge/Nature.h" +# include "../geometry/Geom.h" +using namespace std; + +#include "../system/Iterator.h" //soc + +// +// Interface0D +// +////////////////////////////////////////////////// + +class FEdge; +class SVertex; +class ViewVertex; +class NonTVertex; +class TVertex; +/*! Base class for any 0D element. */ +class Interface0D +{ +public: + + /*! Default constructor */ + Interface0D() {} + virtual ~Interface0D() {}; //soc + + /*! Returns the string "Interface0D".*/ + virtual string getExactTypeName() const { + return "Interface0D"; + } + + // Data access methods + + /*! Returns the 3D x coordinate of the point. */ + virtual real getX() const { + PyErr_SetString(PyExc_TypeError, "method getX() not properly overridden"); + return 0; + } + + /*! Returns the 3D y coordinate of the point. */ + virtual real getY() const { + PyErr_SetString(PyExc_TypeError, "method getY() not properly overridden"); + return 0; + } + + /*! Returns the 3D z coordinate of the point. */ + virtual real getZ() const { + PyErr_SetString(PyExc_TypeError, "method getZ() not properly overridden"); + return 0; + } + + /*! Returns the 3D point. */ + virtual Geometry::Vec3f getPoint3D() const { + PyErr_SetString(PyExc_TypeError, "method getPoint3D() not properly overridden"); + return 0; + } + + /*! Returns the 2D x coordinate of the point. */ + virtual real getProjectedX() const { + PyErr_SetString(PyExc_TypeError, "method getProjectedX() not properly overridden"); + return 0; + } + + /*! Returns the 2D y coordinate of the point. */ + virtual real getProjectedY() const { + PyErr_SetString(PyExc_TypeError, "method getProjectedY() not properly overridden"); + return 0; + } + + /*! Returns the 2D z coordinate of the point. */ + virtual real getProjectedZ() const { + PyErr_SetString(PyExc_TypeError, "method getProjectedZ() not properly overridden"); + return 0; + } + + /*! Returns the 2D point. */ + virtual Geometry::Vec2f getPoint2D() const { + PyErr_SetString(PyExc_TypeError, "method getPoint2D() not properly overridden"); + return 0; + } + + /*! Returns the FEdge that lies between this Interface0D and the + * Interface0D given as argument. */ + virtual FEdge* getFEdge(Interface0D&) { + PyErr_SetString(PyExc_TypeError, "method getFEdge() not properly overridden"); + return 0; + } + + /*! Returns the Id of the point. */ + virtual Id getId() const { + PyErr_SetString(PyExc_TypeError, "method getId() not properly overridden"); + return 0; + } + + /*! Returns the nature of the point. */ + virtual Nature::VertexNature getNature() const { + PyErr_SetString(PyExc_TypeError, "method getNature() not properly overridden"); + return Nature::POINT; + } + + + /*! Cast the Interface0D in SVertex if it can be. */ + virtual SVertex * castToSVertex(){ + PyErr_SetString(PyExc_TypeError, "method castToSVertex() not properly overridden"); + return 0; + } + + /*! Cast the Interface0D in ViewVertex if it can be. */ + virtual ViewVertex * castToViewVertex(){ + PyErr_SetString(PyExc_TypeError, "method castToViewVertex() not properly overridden"); + return 0; + } + + /*! Cast the Interface0D in NonTVertex if it can be. */ + virtual NonTVertex * castToNonTVertex(){ + PyErr_SetString(PyExc_TypeError, "method castToNonTVertex() not properly overridden"); + return 0; + } + + /*! Cast the Interface0D in TVertex if it can be. */ + virtual TVertex * castToTVertex(){ + PyErr_SetString(PyExc_TypeError, "method castToTVertex() not properly overridden"); + return 0; + } + +}; + + +// +// Interface0DIteratorNested +// +////////////////////////////////////////////////// + +class Interface0DIteratorNested : public Iterator +{ +public: + + virtual ~Interface0DIteratorNested() {} + + virtual string getExactTypeName() const { + return "Interface0DIteratorNested"; + } + + virtual Interface0D& operator*() = 0; + + virtual Interface0D* operator->() { + return &(operator*()); + } + + virtual int increment() = 0; + + virtual int decrement() = 0; + + virtual bool isBegin() const = 0; + + virtual bool isEnd() const = 0; + + virtual bool operator==(const Interface0DIteratorNested& it) const = 0; + + virtual bool operator!=(const Interface0DIteratorNested& it) const { + return !(*this == it); + } + + /*! Returns the curvilinear abscissa */ + virtual float t() const = 0; + /*! Returns the point parameter 0<u<1 */ + virtual float u() const = 0; + + virtual Interface0DIteratorNested* copy() const = 0; +}; + + +// +// Interface0DIterator +// +////////////////////////////////////////////////// + +/*! Class defining an iterator over Interface0D elements. + * An instance of this iterator is always obtained + * from a 1D element. + * \attention In the scripting language, you must call + * \code it2 = Interface0DIterator(it1) \endcode instead of \code it2 = it1 \endcode + * where \a it1 and \a it2 are 2 Interface0DIterator. + * Otherwise, incrementing \a it1 will also increment \a it2. + */ +class Interface0DIterator : public Iterator +{ +public: + + Interface0DIterator(Interface0DIteratorNested* it = NULL) { + _iterator = it; + } + + /*! Copy constructor */ + Interface0DIterator(const Interface0DIterator& it) { + _iterator = it._iterator->copy(); + } + + /*! Destructor */ + virtual ~Interface0DIterator() { + if (_iterator) + delete _iterator; + } + + /*! Operator = + * \attention In the scripting language, you must call + * \code it2 = Interface0DIterator(it1) \endcode instead of \code it2 = it1 \endcode + * where \a it1 and \a it2 are 2 Interface0DIterator. + * Otherwise, incrementing \a it1 will also increment \a it2. + */ + Interface0DIterator& operator=(const Interface0DIterator& it) { + if(_iterator) + delete _iterator; + _iterator = it._iterator->copy(); + return *this; + } + + /*! Returns the string "Interface0DIterator". */ + virtual string getExactTypeName() const { + if (!_iterator) + return "Interface0DIterator"; + return _iterator->getExactTypeName() + "Proxy"; + } + + // FIXME test it != 0 (exceptions ?) + + /*! Returns a reference to the pointed Interface0D. + * In the scripting language, you must call + * "getObject()" instead using this operator. + */ + Interface0D& operator*() { + return _iterator->operator*(); + } + + /*! Returns a pointer to the pointed Interface0D. + * Can't be called in the scripting language. + */ + Interface0D* operator->() { + return &(operator*()); + } + + /*! Increments. In the scripting language, call + * "increment()". + */ + Interface0DIterator& operator++() { + _iterator->increment(); + return *this; + } + + /*! Increments. In the scripting language, call + * "increment()". + */ + Interface0DIterator operator++(int) { + Interface0DIterator ret(*this); + _iterator->increment(); + return ret; + } + + /*! Decrements. In the scripting language, call + * "decrement()". + */ + Interface0DIterator& operator--() { + _iterator->decrement(); + return *this; + } + + /*! Decrements. In the scripting language, call + * "decrement()". + */ + Interface0DIterator operator--(int) { + Interface0DIterator ret(*this); + _iterator->decrement(); + return ret; + } + + /*! Increments. */ + virtual int increment() { + return _iterator->increment(); + } + + /*! Decrements. */ + virtual int decrement() { + return _iterator->decrement(); + } + + /*! Returns true if the pointed Interface0D is the + * first of the 1D element containing the points over + * which we're iterating. + */ + virtual bool isBegin() const { + return _iterator->isBegin(); + } + + /*! Returns true if the pointed Interface0D is after the + * after the last point of the 1D element we're iterating from. + */ + virtual bool isEnd() const { + return _iterator->isEnd(); + } + + /*! operator == . */ + bool operator==(const Interface0DIterator& it) const { + return _iterator->operator==(*(it._iterator)); + } + + /*! operator != . */ + bool operator!=(const Interface0DIterator& it) const { + return !(*this == it); + } + + /*! Returns the curvilinear abscissa. */ + inline float t() const { + return _iterator->t(); + } + /*! Returns the point parameter in the curve 0<=u<=1. */ + inline float u() const { + return _iterator->u(); + } +protected: + + Interface0DIteratorNested* _iterator; +}; + +#endif // INTERFACE0D_H diff --git a/source/blender/freestyle/intern/view_map/Interface1D.h b/source/blender/freestyle/intern/view_map/Interface1D.h new file mode 100755 index 00000000000..60cc0ebcb7e --- /dev/null +++ b/source/blender/freestyle/intern/view_map/Interface1D.h @@ -0,0 +1,226 @@ +// +// Filename : Interface1D.h +// Author(s) : Emmanuel Turquin +// Purpose : Interface to 1D elts +// Date of creation : 01/07/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef INTERFACE1D_H +# define INTERFACE1D_H + +# include <Python.h> +# include <string> +# include <iostream> +# include <float.h> +# include "../system/Id.h" +# include "../system/Precision.h" +# include "../winged_edge/Nature.h" +# include "Functions0D.h" + +using namespace std; +/*! \file Interface1D.h + * Interface1D and related tools definitions + */ +// Integration method +/*! The different integration + * methods that can be invoked + * to integrate into a single value the set of values obtained + * from each 0D element of a 1D element. + */ +typedef enum { + MEAN,/*!< The value computed for the 1D element is the mean of the values obtained for the 0D elements.*/ + MIN,/*!< The value computed for the 1D element is the minimum of the values obtained for the 0D elements.*/ + MAX,/*!< The value computed for the 1D element is the maximum of the values obtained for the 0D elements.*/ + FIRST,/*!< The value computed for the 1D element is the first of the values obtained for the 0D elements.*/ + LAST/*!< The value computed for the 1D element is the last of the values obtained for the 0D elements.*/ +} IntegrationType; + +/*! Returns a single + * value from a set of values evaluated at each 0D element + * of this 1D element. + * \param fun + * The UnaryFunction0D used to compute a value at each Interface0D. + * \param it + * The Interface0DIterator used to iterate over the 0D elements of + * this 1D element. The integration will occur over the 0D elements + * starting from the one pointed by it. + * \param it_end + * The Interface0DIterator pointing the end of the 0D elements of the + * 1D element. + * \param integration_type + * The integration method used to compute a single value from + * a set of values. + * \return the single value obtained for the 1D element. + */ +template <class T> +T integrate(UnaryFunction0D<T>& fun, + Interface0DIterator it, + Interface0DIterator it_end, + IntegrationType integration_type = MEAN) { + T res; + unsigned size; + switch (integration_type) { + case MIN: + fun(it); + res = fun.result;++it; + for (; !it.isEnd(); ++it) { + fun(it); + if (fun.result < res) + res = fun.result; + } + break; + case MAX: + fun(it); + res = fun.result;++it; + for (; !it.isEnd(); ++it) { + fun(it); + if (fun.result > res) + res = fun.result; + } + break; + case FIRST: + fun(it); + res = fun.result; + break; + case LAST: + fun(--it_end); + res = fun.result; + break; + case MEAN: + default: + fun(it); + res = fun.result;++it; + for (size = 1; !it.isEnd(); ++it, ++size) { + fun(it); + res += fun.result; + } + res /= (size ? size : 1); + break; + } + return res; +} + +// +// Interface1D +// +////////////////////////////////////////////////// + +/*! Base class for any 1D element. */ +class Interface1D +{ +public: + + /*! Default constructor */ + Interface1D() {_timeStamp=0;} + virtual ~Interface1D() {}; //soc + + /*! Returns the string "Interface1D" .*/ + virtual string getExactTypeName() const { + return "Interface1D"; + } + + // Iterator access + + /*! Returns an iterator over the Interface1D vertices, + * pointing to the first vertex. + */ + virtual Interface0DIterator verticesBegin() { + PyErr_SetString(PyExc_TypeError, "method verticesBegin() not properly overridden"); + return Interface0DIterator(); + } + + /*! Returns an iterator over the Interface1D vertices, + * pointing after the last vertex. + */ + virtual Interface0DIterator verticesEnd(){ + PyErr_SetString(PyExc_TypeError, "method verticesEnd() not properly overridden"); + return Interface0DIterator(); + } + + /*! Returns an iterator over the Interface1D points, + * pointing to the first point. The difference with + * verticesBegin() is that here we can iterate over + * points of the 1D element at a any given sampling. + * Indeed, for each iteration, a virtual point is created. + * \param t + * The sampling with which we want to iterate over points of + * this 1D element. + */ + virtual Interface0DIterator pointsBegin(float t=0.f) { + PyErr_SetString(PyExc_TypeError, "method pointsBegin() not properly overridden"); + return Interface0DIterator(); + } + + /*! Returns an iterator over the Interface1D points, + * pointing after the last point. The difference with + * verticesEnd() is that here we can iterate over + * points of the 1D element at a any given sampling. + * Indeed, for each iteration, a virtual point is created. + * \param t + * The sampling with which we want to iterate over points of + * this 1D element. + */ + virtual Interface0DIterator pointsEnd(float t=0.f) { + PyErr_SetString(PyExc_TypeError, "method pointsEnd() not properly overridden"); + return Interface0DIterator(); + } + + // Data access methods + + /*! Returns the 2D length of the 1D element. */ + virtual real getLength2D() const { + PyErr_SetString(PyExc_TypeError, "method getLength2D() not properly overridden"); + return 0; + } + + /*! Returns the Id of the 1D element .*/ + virtual Id getId() const { + PyErr_SetString(PyExc_TypeError, "method getId() not properly overridden"); + return Id(0, 0); + } + + + // FIXME: ce truc n'a rien a faire la...(c une requete complexe qui doit etre ds les Function1D) + /*! Returns the nature of the 1D element. */ + virtual Nature::EdgeNature getNature() const { + PyErr_SetString(PyExc_TypeError, "method getNature() not properly overridden"); + return Nature::NO_FEATURE; + } + + /*! Returns the time stamp of the 1D element. Mainly used for selection. */ + virtual unsigned getTimeStamp() const { + return _timeStamp; + } + + /*! Sets the time stamp for the 1D element. */ + inline void setTimeStamp(unsigned iTimeStamp){ + _timeStamp = iTimeStamp; + } + +protected: + unsigned _timeStamp; +}; + +#endif // INTERFACE1D_H diff --git a/source/blender/freestyle/intern/view_map/Silhouette.cpp b/source/blender/freestyle/intern/view_map/Silhouette.cpp new file mode 100755 index 00000000000..7a7d0a51d4b --- /dev/null +++ b/source/blender/freestyle/intern/view_map/Silhouette.cpp @@ -0,0 +1,370 @@ + +// +// 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 "Silhouette.h" +#include "ViewMap.h" + + /**********************************/ + /* */ + /* */ + /* SVertex */ + /* */ + /* */ + /**********************************/ + +Nature::VertexNature SVertex::getNature() const { + Nature::VertexNature nature = Nature::S_VERTEX; + if (_pViewVertex) + nature |= _pViewVertex->getNature(); + return nature; +} + +SVertex * SVertex::castToSVertex(){ + return this; +} + +ViewVertex * SVertex::castToViewVertex(){ + return _pViewVertex; +} + +NonTVertex * SVertex::castToNonTVertex(){ + return dynamic_cast<NonTVertex*>(_pViewVertex); +} + +TVertex * SVertex::castToTVertex(){ + return dynamic_cast<TVertex*>(_pViewVertex); +} + +float SVertex::shape_importance() const +{ + return shape()->importance(); +} + +//Material SVertex::material() const {return _Shape->material();} +Id SVertex::shape_id() const {return _Shape->getId();} +const SShape * SVertex::shape() const {return _Shape;} + +const int SVertex::qi() const +{ + if (getNature() & Nature::T_VERTEX) + Exception::raiseException(); + return (_FEdges[0])->qi(); +} + +occluder_container::const_iterator SVertex::occluders_begin() const +{ + if (getNature() & Nature::T_VERTEX) + Exception::raiseException(); + return (_FEdges[0])->occluders_begin(); +} + +occluder_container::const_iterator SVertex::occluders_end() const +{ + if (getNature() & Nature::T_VERTEX) + Exception::raiseException(); + return (_FEdges[0])->occluders_end(); +} + +bool SVertex::occluders_empty() const +{ + if (getNature() & Nature::T_VERTEX) + Exception::raiseException(); + return (_FEdges[0])->occluders_empty(); +} + +int SVertex::occluders_size() const +{ + if (getNature() & Nature::T_VERTEX) + Exception::raiseException(); + return (_FEdges[0])->occluders_size(); +} + +const Polygon3r& SVertex::occludee() const +{ + if (getNature() & Nature::T_VERTEX) + Exception::raiseException(); + return (_FEdges[0])->occludee(); +} + +const SShape* SVertex::occluded_shape() const +{ + if (getNature() & Nature::T_VERTEX) + Exception::raiseException(); + return (_FEdges[0])->occluded_shape(); +} + +const bool SVertex::occludee_empty() const +{ + if (getNature() & Nature::T_VERTEX) + Exception::raiseException(); + return (_FEdges[0])->occludee_empty(); +} + +real SVertex::z_discontinuity() const +{ + if (getNature() & Nature::T_VERTEX) + Exception::raiseException(); + return (_FEdges[0])->z_discontinuity(); +} + +FEdge* SVertex::fedge() +{ + if (getNature() & Nature::T_VERTEX) + return 0; + return _FEdges[0]; +} + +FEdge* SVertex::getFEdge(Interface0D& inter) +{ + FEdge * result = 0; + SVertex* iVertexB = dynamic_cast<SVertex*>(&inter); + if (!iVertexB) + return result; + vector<FEdge*>::const_iterator fe=_FEdges.begin(), feend=_FEdges.end(); + for(; + fe!=feend; + ++fe) + { + if( (((*fe)->vertexA() == this) && ((*fe)->vertexB() == iVertexB)) + || (((*fe)->vertexB() == this) && ((*fe)->vertexA() == iVertexB))) + result = (*fe); + } + if((result == 0) && (getNature() & Nature::T_VERTEX)) + { + SVertex *brother; + ViewVertex *vvertex = viewvertex(); + TVertex * tvertex = dynamic_cast<TVertex*>(vvertex); + if(tvertex) + { + brother = tvertex->frontSVertex(); + if(this == brother) + brother = tvertex->backSVertex(); + const vector<FEdge*>& fedges = brother->fedges(); + for(fe=fedges.begin(),feend=fedges.end(); + fe!=feend; + ++fe) + { + if( (((*fe)->vertexA() == brother) && ((*fe)->vertexB() == iVertexB)) + || (((*fe)->vertexB() == brother) && ((*fe)->vertexA() == iVertexB))) + result = (*fe); + } + } + } + if((result == 0) && (iVertexB->getNature() & Nature::T_VERTEX)) + { + SVertex *brother; + ViewVertex *vvertex = iVertexB->viewvertex(); + TVertex * tvertex = dynamic_cast<TVertex*>(vvertex); + if(tvertex) + { + brother = tvertex->frontSVertex(); + if(iVertexB == brother) + brother = tvertex->backSVertex(); + for(fe=_FEdges.begin(),feend=_FEdges.end(); + fe!=feend; + ++fe) + { + if( (((*fe)->vertexA() == this) && ((*fe)->vertexB() == brother)) + || (((*fe)->vertexB() == this) && ((*fe)->vertexA() == brother))) + result = (*fe); + } + } + } + + return result; +} + + + /**********************************/ + /* */ + /* */ + /* FEdge */ + /* */ + /* */ + /**********************************/ + + +int FEdge::viewedge_nature() const {return _ViewEdge->getNature();} +//float FEdge::viewedge_length() const {return _ViewEdge->viewedge_length();} +const SShape* FEdge::occluded_shape() const +{ + ViewShape * aShape = _ViewEdge->aShape(); + if(aShape == 0) + return 0; + return aShape->sshape(); +} + +float FEdge::shape_importance() const +{ + return _VertexA->shape()->importance(); +} + +int FEdge::invisibility() const +{ + return _ViewEdge->qi(); +} + +occluder_container::const_iterator FEdge::occluders_begin() const {return _ViewEdge->occluders_begin();} +occluder_container::const_iterator FEdge::occluders_end() const {return _ViewEdge->occluders_end();} +bool FEdge::occluders_empty() const {return _ViewEdge->occluders_empty();} +int FEdge::occluders_size() const {return _ViewEdge->occluders_size();} +const bool FEdge::occludee_empty() const +{ + return _ViewEdge->occludee_empty(); +} + + + +Id FEdge::shape_id() const +{ + return _VertexA->shape()->getId(); +} +const SShape* FEdge::shape() const +{ + return _VertexA->shape(); +} + +real FEdge::z_discontinuity() const +{ + if(!(getNature() & Nature::SILHOUETTE) && !(getNature() & Nature::BORDER)) + { + return 0; + } + + BBox<Vec3r> box = ViewMap::getInstance()->getScene3dBBox(); + + Vec3r bbox_size_vec(box.getMax() - box.getMin()); + real bboxsize = bbox_size_vec.norm(); + if(occludee_empty()) + + { + //return FLT_MAX; + + return 1.0; + + //return bboxsize; + + } + // real result; + // z_discontinuity_functor<SVertex> _functor; + + // Evaluate<SVertex,z_discontinuity_functor<SVertex> >(&_functor, iCombination, result ) + Vec3r middle((_VertexB->point3d()-_VertexA->point3d())); + + middle /= 2; + Vec3r disc_vec(middle - _occludeeIntersection); + real res = disc_vec.norm() / bboxsize; + return res; + + //return fabs((middle.z()-_occludeeIntersection.z())); +} + + +//float FEdge::local_average_depth(int iCombination ) const +//{ +// +// float result; +// local_average_depth_functor<SVertex> functor; +// Evaluate(&functor, iCombination, result); +// +// return result; +//} +//float FEdge::local_depth_variance(int iCombination ) const +//{ +// float result; +// +// local_depth_variance_functor<SVertex> functor; +// +// Evaluate(&functor, iCombination, result); +// +// return result; +//} +// +// +//real FEdge::local_average_density( float sigma, int iCombination) const +//{ +// float result; +// +// density_functor<SVertex> functor(sigma); +// +// Evaluate(&functor, iCombination, result); +// +// return result; +//} +// +////Vec3r FEdge::normal(int& oException /* = Exception::NO_EXCEPTION */) +////{ +//// Vec3r Na = _VertexA->normal(oException); +//// if(oException != Exception::NO_EXCEPTION) +//// return Na; +//// Vec3r Nb = _VertexB->normal(oException); +//// if(oException != Exception::NO_EXCEPTION) +//// return Nb; +//// return (Na+Nb)/2.0; +////} +// +//Vec3r FEdge::curvature2d_as_vector(int iCombination) const +//{ +// Vec3r result; +// curvature2d_as_vector_functor<SVertex> _functor; +// Evaluate<Vec3r,curvature2d_as_vector_functor<SVertex> >(&_functor, iCombination, result ); +// return result; +//} +// +//real FEdge::curvature2d_as_angle(int iCombination) const +//{ +// real result; +// curvature2d_as_angle_functor<SVertex> _functor; +// Evaluate<real,curvature2d_as_angle_functor<SVertex> >(&_functor, iCombination, result ); +// return result; +//} + + /**********************************/ + /* */ + /* */ + /* FEdgeSharp */ + /* */ + /* */ + /**********************************/ + +//Material FEdge::material() const +//{ +// return _VertexA->shape()->material(); +//} +const FrsMaterial& FEdgeSharp::aFrsMaterial() const { + return _VertexA->shape()->frs_material(_aFrsMaterialIndex); +} + +const FrsMaterial& FEdgeSharp::bFrsMaterial() const { + return _VertexA->shape()->frs_material(_bFrsMaterialIndex); +} + + /**********************************/ + /* */ + /* */ + /* FEdgeSmooth */ + /* */ + /* */ + /**********************************/ + +const FrsMaterial& FEdgeSmooth::frs_material() const { + return _VertexA->shape()->frs_material(_FrsMaterialIndex); +} diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h new file mode 100755 index 00000000000..fc0bff9cbff --- /dev/null +++ b/source/blender/freestyle/intern/view_map/Silhouette.h @@ -0,0 +1,1429 @@ +// +// Filename : Silhouette.h +// Author(s) : Stephane Grabli +// Purpose : Classes to define a silhouette structure +// Date of creation : 25/03/2002 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef SILHOUETTE_H +# define SILHOUETTE_H + +# include "Interface0D.h" +# include "Interface1D.h" +# include <iostream> +# include <string> +# include <vector> +# include <set> +# include <float.h> +# include "../system/FreestyleConfig.h" +# include "../geometry/Geom.h" +# include "../geometry/BBox.h" +# include "../scene_graph/FrsMaterial.h" +# include "../geometry/Polygon.h" +# include "../system/Exception.h" +# include "../winged_edge/Curvature.h" + +using namespace std; +using namespace Geometry; + +class ViewShape; +typedef vector<ViewShape*> occluder_container; + + /**********************************/ + /* */ + /* */ + /* SVertex */ + /* */ + /* */ + /**********************************/ + +class FEdge; +class ViewVertex; +class SShape; + +/*! Class to define a vertex of the embedding. */ +class LIB_VIEW_MAP_EXPORT SVertex : public Interface0D +{ +public: // Implementation of Interface0D + + /*! Returns the string "SVertex" .*/ + virtual string getExactTypeName() const { + return "SVertex"; + } + + // Data access methods + + /*! Returns the 3D x coordinate of the vertex .*/ + virtual real getX() const { + return _Point3D.x(); + } + + /*! Returns the 3D y coordinate of the vertex .*/ + virtual real getY() const { + return _Point3D.y(); + } + + /*! Returns the 3D z coordinate of the vertex .*/ + virtual real getZ() const { + return _Point3D.z(); + } + + /*! Returns the 3D point. */ + virtual Vec3f getPoint3D() const { + return _Point3D; + } + + /*! Returns the projected 3D x coordinate of the vertex .*/ + virtual real getProjectedX() const { + return _Point2D.x(); + } + + /*! Returns the projected 3D y coordinate of the vertex .*/ + virtual real getProjectedY() const { + return _Point2D.y(); + } + + /*! Returns the projected 3D z coordinate of the vertex .*/ + virtual real getProjectedZ() const { + return _Point2D.z(); + } + + /*! Returns the 2D point. */ + virtual Vec2f getPoint2D() const { + return Vec2f((float)_Point2D.x(),(float)_Point2D.y()); + } + + /*! Returns the FEdge that lies between this Svertex and the + * Interface0D given as argument. */ + virtual FEdge* getFEdge(Interface0D&); + + /*! Returns the Id of the vertex .*/ + virtual Id getId() const { + return _Id; + } + + /*! Returns the nature of the vertex .*/ + virtual Nature::VertexNature getNature() const; + + /*! Cast the Interface0D in SVertex if it can be. */ + virtual SVertex * castToSVertex(); + + /*! Cast the Interface0D in ViewVertex if it can be. */ + virtual ViewVertex * castToViewVertex(); + + /*! Cast the Interface0D in NonTVertex if it can be. */ + virtual NonTVertex * castToNonTVertex(); + + /*! Cast the Interface0D in TVertex if it can be. */ + virtual TVertex * castToTVertex(); + +public: + + typedef vector<FEdge*> fedges_container; + +private: + + Id _Id; + Vec3r _Point3D; + Vec3r _Point2D; + set<Vec3r> _Normals; + vector<FEdge*> _FEdges; // the edges containing this vertex + SShape *_Shape; // the shape to which belongs the vertex + ViewVertex *_pViewVertex; // The associated viewvertex, in case there is one. + real _curvatureFredo; + Vec2r _directionFredo; + CurvatureInfo* _curvature_info; + +public: + + /*! A field that can be used by the user to store any data. + * This field must be reseted afterwards using ResetUserData(). + */ + void *userdata; + + /*! Default constructor.*/ + inline SVertex() { + _Id = 0; + userdata = NULL; + _Shape = NULL; + _pViewVertex = 0; + _curvature_info = 0; + } + + /*! Builds a SVertex from 3D coordinates and an Id. */ + inline SVertex(const Vec3r &iPoint3D, const Id& id) { + _Point3D = iPoint3D; + _Id=id; + userdata = NULL; + _Shape = NULL; + _pViewVertex=0; + _curvature_info = 0; + } + + /*! Copy constructor. */ + inline SVertex(SVertex& iBrother) { + _Id = iBrother._Id; + _Point3D = iBrother.point3D(); + _Point2D = iBrother.point2D(); + _Normals = iBrother._Normals; + _FEdges = iBrother.fedges(); + _Shape = iBrother.shape(); + _pViewVertex = iBrother._pViewVertex; + if (!(iBrother._curvature_info)) + _curvature_info = 0; + else + _curvature_info = new CurvatureInfo(*(iBrother._curvature_info)); + iBrother.userdata = this; + userdata = 0; + } + + /*! Destructor. */ + virtual ~SVertex() { + if (_curvature_info) + delete _curvature_info; + } + + /*! Cloning method. */ + virtual SVertex * duplicate() { + SVertex *clone = new SVertex(*this); + return clone; + } + + /*! operator == */ + virtual bool operator==(const SVertex& iBrother) { + return ((_Point2D == iBrother._Point2D) && + (_Point3D == iBrother._Point3D)); + } + + /* accessors */ + inline const Vec3r& point3D() const {return _Point3D;} + inline const Vec3r& point2D() const {return _Point2D;} + /*! Returns the set of normals for this Vertex. + * In a smooth surface, a vertex has exactly one normal. + * In a sharp surface, a vertex can have any number of normals. + */ + inline set<Vec3r> normals() {return _Normals;} + /*! Returns the number of different normals for this vertex. */ + inline unsigned normalsSize() const {return _Normals.size();} + inline const vector<FEdge*>& fedges() {return _FEdges;} + inline fedges_container::iterator fedges_begin() {return _FEdges.begin();} + inline fedges_container::iterator fedges_end() {return _FEdges.end();} + inline SShape * shape() {return _Shape;} + inline real z() const {return _Point2D[2];} + /*! If this SVertex is also a ViewVertex, this method + * returns a pointer onto this ViewVertex. 0 is returned + * otherwise. + */ + inline ViewVertex * viewvertex() {return _pViewVertex;} + + /*! modifiers */ + /*! Sets the 3D coordinates of the SVertex. */ + inline void setPoint3D(const Vec3r &iPoint3D) {_Point3D = iPoint3D;} + /*! Sets the 3D projected coordinates of the SVertex. */ + inline void setPoint2D(const Vec3r &iPoint2D) {_Point2D = iPoint2D;} + /*! Adds a normal to the Svertex's set of normals. If the same + * normal is already in the set, nothing changes. + */ + inline void AddNormal(const Vec3r& iNormal) + { + _Normals.insert(iNormal); // if iNormal in the set already exists, nothing is done + } + + void setCurvatureInfo(CurvatureInfo* ci) { + _curvature_info = ci; + } + + const CurvatureInfo* getCurvatureInfo() const { + return _curvature_info; + } + + /* Fredo's normal and curvature*/ + void setCurvatureFredo(real c) {_curvatureFredo=c;} + void setDirectionFredo(Vec2r d) {_directionFredo=d;} + real curvatureFredo () {return _curvatureFredo;} + const Vec2r directionFredo () {return _directionFredo;} + + /*! Sets the Id */ + inline void setId(const Id& id) {_Id = id;} + inline void setFEdges(const vector<FEdge*>& iFEdges) {_FEdges = iFEdges;} + inline void setShape(SShape *iShape) {_Shape = iShape;} + inline void setViewVertex(ViewVertex *iViewVertex) {_pViewVertex = iViewVertex;} + /*! Add an FEdge to the list of edges emanating from this SVertex. */ + inline void AddFEdge(FEdge* iFEdge) {_FEdges.push_back(iFEdge);} + /* replaces edge 1 by edge 2 in the list of edges */ + inline void Replace(FEdge *e1, FEdge *e2) + { + vector<FEdge*>::iterator insertedfe; + for(vector<FEdge*>::iterator fe=_FEdges.begin(),fend=_FEdges.end(); + fe!=fend; + fe++) + { + if((*fe) == e1) + { + insertedfe = _FEdges.insert(fe, e2);// inserts e2 before fe. + // returns an iterator pointing toward e2. fe is invalidated. + // we want to remove e1, but we can't use fe anymore: + insertedfe++; // insertedfe points now to e1 + _FEdges.erase(insertedfe); + return; + } + } + } + +public: + + /* Information access interface */ + + FEdge *fedge() ; // for non T vertex + inline const Vec3r& point2d() const {return point2D();} + inline const Vec3r& point3d() const {return point3D();} + inline Vec3r normal() const {if(_Normals.size() == 1) return (*(_Normals.begin())); Exception::raiseException(); return *(_Normals.begin());} + //Material material() const ; + Id shape_id() const ; + const SShape* shape() const ; + float shape_importance() const ; + + const int qi() const ; + occluder_container::const_iterator occluders_begin() const ; + occluder_container::const_iterator occluders_end() const ; + bool occluders_empty() const ; + int occluders_size() const ; + const Polygon3r& occludee() const ; + const SShape * occluded_shape() const ; + const bool occludee_empty() const ; + real z_discontinuity() const ; + //inline float local_average_depth() const ; + // inline float local_depth_variance() const ; + // inline real local_average_density(float sigma = 2.3f) const ; + //inline Vec3r shaded_color() const ; + // inline Vec3r orientation2d() const ; + // inline Vec3r orientation3d() const ; + // inline Vec3r curvature2d_as_vector() const ; + /*! angle in radians */ + // inline real curvature2d_as_angle() const ; + +}; + + /**********************************/ + /* */ + /* */ + /* FEdge */ + /* */ + /* */ + /**********************************/ + + +class ViewEdge; +/*! Base Class for feature edges. + * This FEdge can represent a silhouette, a crease, + * a ridge/valley, a border or a suggestive contour. + * For silhouettes, the FEdge is oriented + * such as, the visible face lies on the left of the edge. + * For borders, the FEdge is oriented + * such as, the face lies on the left of the edge. + * An FEdge can represent an initial edge of the mesh + * or runs accross a face of the initial mesh depending + * on the smoothness or sharpness of the mesh. + * This class is specialized into a smooth and a sharp + * version since their properties slightly vary from + * one to the other. + */ +class LIB_VIEW_MAP_EXPORT FEdge : public Interface1D +{ +public: // Implementation of Interface0D + + /*! Returns the string "FEdge" . */ + virtual string getExactTypeName() const { + return "FEdge"; + } + + // Data access methods + + /*! Returns the 2D length of the FEdge. */ + virtual real getLength2D() const { + if (!_VertexA || !_VertexB) + return 0; + return (_VertexB->getPoint2D() - _VertexA->getPoint2D()).norm(); + } + + /*! Returns the Id of the FEdge. */ + virtual Id getId() const { + return _Id; + } + +public: + + // An edge can only be of one kind (SILHOUETTE or BORDER, etc...) + // For an multi-nature edge there must be several different FEdge. + // DEBUG: + // Vec3r A; + // Vec3r u; + // vector<Polygon3r> _Occludees; + // Vec3r intersection; + // vector<Vec3i> _Cells; + +protected: + SVertex *_VertexA; + SVertex *_VertexB; + Id _Id; + Nature::EdgeNature _Nature; + //vector<Polygon3r> _Occluders; // visibility // NON GERE PAR LE COPY CONSTRUCTOR!! + + FEdge *_NextEdge; // next edge on the chain + FEdge *_PreviousEdge; + ViewEdge *_ViewEdge; + // Sometimes we need to deport the visibility computation onto another + // edge. For example the exact edges use edges of the mesh to + // compute their visibility + + Polygon3r _aFace; // The occluded face which lies on the right of a silhouette edge + Vec3r _occludeeIntersection; + bool _occludeeEmpty; + + bool _isSmooth; + +public: + /*! A field that can be used by the user to store any data. + * This field must be reseted afterwards using ResetUserData(). + */ + void *userdata; + /*! Default constructor */ + inline FEdge() { + userdata = NULL; + _VertexA = NULL; + _VertexB = NULL; + _Nature = Nature::NO_FEATURE; + _NextEdge = NULL; + _PreviousEdge = NULL; + _ViewEdge = NULL; + //_hasVisibilityPoint=false; + _occludeeEmpty = true; + _isSmooth = false; + } + /*! Builds an FEdge going from vA to vB. */ + inline FEdge(SVertex *vA, SVertex *vB) { + userdata = NULL; + _VertexA = vA; + _VertexB = vB; + _Nature = Nature::NO_FEATURE; + _NextEdge=NULL; + _PreviousEdge=NULL; + _ViewEdge = NULL; + //_hasVisibilityPoint=false; + _occludeeEmpty = true; + _isSmooth = false; + } + /*! Copy constructor */ + inline FEdge(FEdge& iBrother) + { + _VertexA = iBrother.vertexA(); + _VertexB = iBrother.vertexB(); + _NextEdge = iBrother.nextEdge(); + _PreviousEdge = iBrother._PreviousEdge; + _Nature = iBrother.getNature(); + _Id = iBrother._Id; + _ViewEdge = iBrother._ViewEdge; + //_hasVisibilityPoint = iBrother._hasVisibilityPoint; + //_VisibilityPointA = iBrother._VisibilityPointA; + //_VisibilityPointB = iBrother._VisibilityPointB; + _aFace = iBrother._aFace; + _occludeeEmpty = iBrother._occludeeEmpty; + _isSmooth = iBrother._isSmooth; + iBrother.userdata = this; + userdata = 0; + } + /*! Destructor */ + virtual ~FEdge() {} + /*! Cloning method. */ + virtual FEdge* duplicate() + { + FEdge *clone = new FEdge(*this); + return clone; + } + /* accessors */ + /*! Returns the first SVertex. */ + inline SVertex* vertexA() {return _VertexA;} + /*! Returns the second SVertex. */ + inline SVertex* vertexB() {return _VertexB;} + /*! Returns the first SVertex if i=0, the seccond SVertex + * if i=1. */ + inline SVertex* operator[](const unsigned short int& i) const{ + return i%2==0 ? _VertexA : _VertexB; + } + /*! Returns the nature of the FEdge. */ + inline Nature::EdgeNature getNature() const {return _Nature;} + /*! Returns the FEdge following this one in the ViewEdge. + * If this FEdge is the last of the ViewEdge, 0 is returned. + */ + inline FEdge * nextEdge() {return _NextEdge;} + /*! Returns the Edge preceding this one in the ViewEdge. + * If this FEdge is the first one of the ViewEdge, 0 is returned. + */ + inline FEdge * previousEdge() {return _PreviousEdge;} + inline SShape * shape() {return _VertexA->shape();} + //inline int invisibility() const {return _Occluders.size();} + int invisibility() const ; + //inline const vector<Polygon3r>& occluders() const {return _Occluders;} + /*! Returns a pointer to the ViewEdge to which this FEdge belongs to. */ + inline ViewEdge * viewedge() const {return _ViewEdge;} + inline Vec3r center3d() {return Vec3r((_VertexA->point3D()+_VertexB->point3D())/2.0);} + inline Vec3r center2d() {return Vec3r((_VertexA->point2D()+_VertexB->point2D())/2.0);} + // inline bool hasVisibilityPoint() const {return _hasVisibilityPoint;} + // inline Vec3r visibilityPointA() const {return _VisibilityPointA;} + // inline Vec3r visibilityPointB() const {return _VisibilityPointB;} + inline const Polygon3r& aFace() const {return _aFace;} + inline const Vec3r& getOccludeeIntersection() { return _occludeeIntersection; } + inline bool getOccludeeEmpty() { return _occludeeEmpty; } + /*! Returns true if this FEdge is a smooth FEdge. */ + inline bool isSmooth() const {return _isSmooth;} + + /* modifiers */ + /*! Sets the first SVertex. */ + inline void setVertexA(SVertex *vA) {_VertexA = vA;} + /*! Sets the second SVertex. */ + inline void setVertexB(SVertex *vB) {_VertexB = vB;} + /*! Sets the FEdge Id . */ + inline void setId(const Id& id) {_Id = id;} + /*! Sets the pointer to the next FEdge. */ + inline void setNextEdge(FEdge* iEdge) {_NextEdge = iEdge;} + /*! Sets the pointer to the previous FEdge. */ + inline void setPreviousEdge(FEdge *iEdge) {_PreviousEdge = iEdge;} + /*! Sets the nature of this FEdge. */ + inline void setNature(Nature::EdgeNature iNature) {_Nature = iNature;} + //inline void AddOccluder(Polygon3r& iPolygon) {_Occluders.push_back(iPolygon);} + /*! Sets the ViewEdge to which this FEdge belongs to. */ + inline void setViewEdge(ViewEdge *iViewEdge) {_ViewEdge = iViewEdge;} + // inline void setHasVisibilityPoint(bool iBool) {_hasVisibilityPoint = iBool;} + // inline void setVisibilityPointA(const Vec3r& iPoint) {_VisibilityPointA = iPoint;} + // inline void setVisibilityPointB(const Vec3r& iPoint) {_VisibilityPointB = iPoint;} + inline void setaFace(Polygon3r& iFace) {_aFace = iFace;} + inline void setOccludeeIntersection(const Vec3r& iPoint) {_occludeeIntersection = iPoint;} + inline void setOccludeeEmpty(bool iempty) {_occludeeEmpty = iempty;} + /*! Sets the flag telling whether this FEdge is smooth or sharp. + * true for Smooth, false for Sharp. + */ + inline void setSmooth(bool iFlag) {_isSmooth = iFlag;} + + /* checks whether two FEdge have a common vertex. + * Returns a pointer on the common vertex if it exists, + * NULL otherwise. + */ + static inline SVertex* CommonVertex(FEdge *iEdge1, FEdge* iEdge2) + { + if((NULL == iEdge1) || (NULL == iEdge2)) + return NULL; + + SVertex *sv1 = iEdge1->vertexA(); + SVertex *sv2 = iEdge1->vertexB(); + SVertex *sv3 = iEdge2->vertexA(); + SVertex *sv4 = iEdge2->vertexB(); + + if((sv1 == sv3) || (sv1 == sv4)) + { + return sv1; + } + else if((sv2 == sv3) || (sv2 == sv4)) + { + return sv2; + } + + return NULL; + } + + inline const SVertex* min2d() const + { + if(_VertexA->point2D() < _VertexB->point2D()) + return _VertexA; + else + return _VertexB; + } + inline const SVertex* max2d() const + { + if(_VertexA->point2D() < _VertexB->point2D()) + return _VertexB; + else + return _VertexA; + } + + /* Information access interface */ + /* Information access interface */ + + //Material material() const ; + Id shape_id() const ; + const SShape * shape() const ; + float shape_importance() const ; + inline const int qi() const {return invisibility();} + occluder_container::const_iterator occluders_begin() const ; + occluder_container::const_iterator occluders_end() const ; + bool occluders_empty() const ; + int occluders_size() const ; + inline const Polygon3r& occludee() const {return aFace();} + const SShape * occluded_shape() const ; + //inline const bool occludee_empty() const {return _occludeeEmpty;} + const bool occludee_empty() const ; + real z_discontinuity() const ; + // inline float local_average_depth(int iCombination = 0) const ; + // inline float local_depth_variance(int iCombination = 0) const ; + // inline real local_average_density(float sigma = 2.3f, int iCombination = 0) const ; + //inline Vec3r shaded_color(int iCombination = 0) const {} + int viewedge_nature() const ; + //float viewedge_length() const ; + inline Vec3r orientation2d() const {return Vec3r(_VertexB->point2d()-_VertexA->point2d());} + inline Vec3r orientation3d() const {return Vec3r(_VertexB->point3d()-_VertexA->point3d());} + // //inline real curvature2d() const {return viewedge()->curvature2d((_VertexA->point2d()+_VertexB->point2d())/2.0);} + // inline Vec3r curvature2d_as_vector(int iCombination = 0) const ; + // /* angle in degrees*/ + // inline real curvature2d_as_angle(int iCombination = 0) const ; + + + // Iterator access (Interface1D) + /*! Returns an iterator over the 2 (!) SVertex + * pointing to the first SVertex. */ + virtual inline Interface0DIterator verticesBegin(); + /*! Returns an iterator over the 2 (!) SVertex + * pointing after the last SVertex. */ + virtual inline Interface0DIterator verticesEnd(); + + /*! Returns an iterator over the FEdge points, + * pointing to the first point. The difference with + * verticesBegin() is that here we can iterate over + * points of the FEdge at a any given sampling. + * Indeed, for each iteration, a virtual point is created. + * \param t + * The sampling with which we want to iterate over points of + * this FEdge. + */ + virtual inline Interface0DIterator pointsBegin(float t=0.f); + /*! Returns an iterator over the FEdge points, + * pointing after the last point. The difference with + * verticesEnd() is that here we can iterate over + * points of the FEdge at a any given sampling. + * Indeed, for each iteration, a virtual point is created. + * \param t + * The sampling with which we want to iterate over points of + * this FEdge. + */ + virtual inline Interface0DIterator pointsEnd(float t=0.f); +}; + +// +// SVertexIterator +// +///////////////////////////////////////////////// + +namespace FEdgeInternal { + + class SVertexIterator : public Interface0DIteratorNested + { + public: + + SVertexIterator() { + _vertex = NULL; + _edge = NULL; + } + + SVertexIterator(const SVertexIterator& vi) { + _vertex = vi._vertex; + _edge = vi._edge; + } + + SVertexIterator(SVertex* v, FEdge* edge) { + _vertex = v; + _edge = edge; + } + + SVertexIterator& operator=(const SVertexIterator& vi) { + _vertex = vi._vertex; + _edge = vi._edge; + return *this; + } + + virtual string getExactTypeName() const { + return "SVertexIterator"; + } + + virtual SVertex& operator*() { + return *_vertex; + } + + virtual SVertex* operator->() { + return &(operator*()); + } + + virtual SVertexIterator& operator++() { + increment(); + return *this; + } + + virtual SVertexIterator operator++(int) { + SVertexIterator ret(*this); + increment(); + return ret; + } + + virtual SVertexIterator& operator--() { + decrement(); + return *this; + } + + virtual SVertexIterator operator--(int) { + SVertexIterator ret(*this); + decrement(); + return ret; + } + + virtual int increment() { + if (_vertex == _edge->vertexB()) { + _vertex = 0; + return 0; + } + + _vertex = _edge->vertexB(); + return 0; + } + + virtual int decrement() { + if (_vertex == _edge->vertexA()) { + _vertex = 0; + return 0; + } + _vertex = _edge->vertexA(); + return 0; + } + + virtual bool isBegin() const { + return _vertex == _edge->vertexA(); + } + + virtual bool isEnd() const { + return _vertex == _edge->vertexB(); + } + + virtual bool operator==(const Interface0DIteratorNested& it) const { + const SVertexIterator* it_exact = dynamic_cast<const SVertexIterator*>(&it); + if (!it_exact) + return false; + return ((_vertex == it_exact->_vertex) && + (_edge == it_exact->_edge)); + } + + virtual float t() const{ + if(_vertex == _edge->vertexA()){ + return 0; + } + return ((float)_edge->getLength2D()); + } + virtual float u() const{ + if(_vertex == _edge->vertexA()){ + return 0; + } + return 1.0; + } + virtual SVertexIterator* copy() const { + return new SVertexIterator(*this); + } + + private: + + SVertex* _vertex; + FEdge* _edge; + }; + +} // end of namespace FEdgeInternal + +// Iterator access (implementation) + +Interface0DIterator FEdge::verticesBegin() { + Interface0DIterator ret(new FEdgeInternal::SVertexIterator(_VertexA, this)); + return ret; +} + +Interface0DIterator FEdge::verticesEnd() { + Interface0DIterator ret(new FEdgeInternal::SVertexIterator(0, this)); + return ret; +} + +Interface0DIterator FEdge::pointsBegin(float t) { + return verticesBegin(); +} + +Interface0DIterator FEdge::pointsEnd(float t) { + return verticesEnd(); +} + +/*! Class defining a sharp FEdge. A Sharp FEdge + * corresponds to an initial edge of the input mesh. + * It can be a silhouette, a crease or a border. + * If it is a crease edge, then it is borded + * by two faces of the mesh. Face a lies on its right + * whereas Face b lies on its left. + * If it is a border edge, then it doesn't have any + * face on its right, and thus Face a = 0. + */ +class LIB_VIEW_MAP_EXPORT FEdgeSharp : public FEdge +{ +protected: + Vec3r _aNormal; // When following the edge, normal of the right face + Vec3r _bNormal; // When following the edge, normal of the left face + unsigned _aFrsMaterialIndex; + unsigned _bFrsMaterialIndex; + +public: + /*! Returns the string "FEdgeSharp" . */ + virtual string getExactTypeName() const { + return "FEdgeSharp"; + } + /*! Default constructor. */ + inline FEdgeSharp() : FEdge(){ + _aFrsMaterialIndex = _bFrsMaterialIndex = 0; + } + /*! Builds an FEdgeSharp going from vA to vB. */ + inline FEdgeSharp(SVertex *vA, SVertex *vB) : FEdge(vA, vB){ + _aFrsMaterialIndex = _bFrsMaterialIndex = 0; + } + /*! Copy constructor. */ + inline FEdgeSharp(FEdgeSharp& iBrother) : FEdge(iBrother){ + _aNormal = iBrother._aNormal; + _bNormal = iBrother._bNormal; + _aFrsMaterialIndex = iBrother._aFrsMaterialIndex; + _bFrsMaterialIndex = iBrother._bFrsMaterialIndex; + } + /*! Destructor. */ + virtual ~FEdgeSharp() {} + /*! Cloning method. */ + virtual FEdge* duplicate(){ + FEdge *clone = new FEdgeSharp(*this); + return clone; + } + /*! Returns the normal to the face lying on the + * right of the FEdge. If this FEdge is a border, + * it has no Face on its right and therefore, no normal. + */ + inline const Vec3r& normalA() {return _aNormal;} + /*! Returns the normal to the face lying on the + * left of the FEdge. + */ + inline const Vec3r& normalB() {return _bNormal;} + /*! Returns the index of the material of the face lying on the + * right of the FEdge. If this FEdge is a border, + * it has no Face on its right and therefore, no material. + */ + inline unsigned aFrsMaterialIndex() const {return _aFrsMaterialIndex;} + /*! Returns the material of the face lying on the + * right of the FEdge. If this FEdge is a border, + * it has no Face on its right and therefore, no material. + */ + const FrsMaterial& aFrsMaterial() const ; + /*! Returns the index of the material of the face lying on the + * left of the FEdge. + */ + inline unsigned bFrsMaterialIndex() const {return _bFrsMaterialIndex;} + /*! Returns the material of the face lying on the + * left of the FEdge. + */ + const FrsMaterial& bFrsMaterial() const ; + + /*! Sets the normal to the face lying on the right of the FEdge. */ + inline void setNormalA(const Vec3r& iNormal) {_aNormal = iNormal;} + /*! Sets the normal to the face lying on the left of the FEdge. */ + inline void setNormalB(const Vec3r& iNormal) {_bNormal = iNormal;} + /*! Sets the index of the material lying on the right of the FEdge.*/ + inline void setaFrsMaterialIndex(unsigned i) {_aFrsMaterialIndex = i;} + /*! Sets the index of the material lying on the left of the FEdge.*/ + inline void setbFrsMaterialIndex(unsigned i) {_bFrsMaterialIndex = i;} + +}; + +/*! Class defining a smooth edge. This kind of edge typically + * runs across a face of the input mesh. It can be + * a silhouette, a ridge or valley, a suggestive contour. + */ +class LIB_VIEW_MAP_EXPORT FEdgeSmooth : public FEdge +{ +protected: + Vec3r _Normal; + unsigned _FrsMaterialIndex; + // bool _hasVisibilityPoint; + // Vec3r _VisibilityPointA; // The edge on which the visibility will be computed represented + // Vec3r _VisibilityPointB; // using its 2 extremity points A and B + void * _Face; // In case of exact silhouette, Face is the WFace crossed by Fedge + // NON GERE PAR LE COPY CONSTRUCTEUR +public: + /*! Returns the string "FEdgeSmooth" . */ + virtual string getExactTypeName() const { + return "FEdgeSmooth"; + } + /*! Default constructor. */ + inline FEdgeSmooth() : FEdge(){ + _Face=0; + _FrsMaterialIndex = 0; + _isSmooth = true; + } + /*! Builds an FEdgeSmooth going from vA to vB. */ + inline FEdgeSmooth(SVertex *vA, SVertex *vB) : FEdge(vA, vB){ + _Face=0; + _FrsMaterialIndex = 0; + _isSmooth = true; + + } + /*! Copy constructor. */ + inline FEdgeSmooth(FEdgeSmooth& iBrother) : FEdge(iBrother){ + _Normal = iBrother._Normal; + _Face = iBrother._Face; + _FrsMaterialIndex = iBrother._FrsMaterialIndex; + _isSmooth = true; + } + /*! Destructor. */ + virtual ~FEdgeSmooth() {} + /*! Cloning method. */ + virtual FEdge* duplicate(){ + FEdge *clone = new FEdgeSmooth(*this); + return clone; + } + + inline void * face() const {return _Face;} + /*! Returns the normal to the Face it is running accross. */ + inline const Vec3r& normal() {return _Normal;} + /*! Returns the index of the material of the face it is running accross. */ + inline unsigned frs_materialIndex() const {return _FrsMaterialIndex;} + /*! Returns the material of the face it is running accross. */ + const FrsMaterial& frs_material() const ; + + inline void setFace(void * iFace) {_Face = iFace;} + /*! Sets the normal to the Face it is running accross. */ + inline void setNormal(const Vec3r& iNormal) {_Normal = iNormal;} + /*! Sets the index of the material of the face it is running accross. */ + inline void setFrsMaterialIndex(unsigned i) {_FrsMaterialIndex = i;} +}; + /**********************************/ + /* */ + /* */ + /* SShape */ + /* */ + /* */ + /**********************************/ + + +/*! Class to define a feature shape. It is the gathering + * of feature elements from an identified input shape + */ +class LIB_VIEW_MAP_EXPORT SShape +{ +private: + vector<FEdge*> _chains; // list of fedges that are chains starting points. + vector<SVertex*> _verticesList; // list of all vertices + vector<FEdge*> _edgesList; // list of all edges + Id _Id; + BBox<Vec3r> _BBox; + vector<FrsMaterial> _FrsMaterials; + + float _importance; + + ViewShape *_ViewShape; + +public: + /*! A field that can be used by the user to store any data. + * This field must be reseted afterwards using ResetUserData(). + */ + void* userdata; // added by E.T. + /*! Default constructor */ + inline SShape() + { + userdata = 0; + + _importance = 0.f; + _ViewShape = 0; + } + /*! Copy constructor */ + inline SShape(SShape& iBrother) + { + userdata = 0; + _Id = iBrother._Id; + _BBox = iBrother.bbox(); + _FrsMaterials = iBrother._FrsMaterials; + + _importance = iBrother._importance; + + _ViewShape = iBrother._ViewShape; + + + //--------- + // vertices + //--------- + vector<SVertex*>::iterator sv,svend; + vector<SVertex*>& verticesList = iBrother.getVertexList(); + for(sv=verticesList.begin(), svend=verticesList.end(); + sv!=svend; + sv++) + { + SVertex *newv = new SVertex(*(*sv)); + newv->setShape(this); + _verticesList.push_back(newv); + } + + //------ + // edges + //------ + vector<FEdge*>::iterator e,eend; + vector<FEdge*>& edgesList = iBrother.getEdgeList(); + for(e=edgesList.begin(),eend=edgesList.end(); + e!=eend; + e++) + { + FEdge *newe = (*e)->duplicate(); + _edgesList.push_back(newe); + } + + //------------------------- + // starting chain edges + //------------------------- + vector<FEdge*>::iterator fe,fend; + vector<FEdge*>& fedges = iBrother.getChains(); + for(fe=fedges.begin(),fend=fedges.end(); + fe!=fend; + fe++) + { + _chains.push_back((FEdge*)((*fe)->userdata)); + } + + + //------------------------- + // remap edges in vertices: + //------------------------- + for(sv=_verticesList.begin(),svend=_verticesList.end(); + sv!=svend; + sv++) + { + const vector<FEdge*>& fedgeList = (*sv)->fedges(); + vector<FEdge*> newfedgelist; + for(vector<FEdge*>::const_iterator fed=fedgeList.begin(),fedend=fedgeList.end(); + fed!=fedend; + fed++) + { + FEdge *current = *fed; + newfedgelist.push_back((FEdge*)current->userdata); + } + (*sv)->setFEdges(newfedgelist); + } + + //------------------------------------- + // remap vertices and nextedge in edges: + //------------------------------------- + for(e=_edgesList.begin(),eend=_edgesList.end(); + e!=eend; + e++) + { + (*e)->setVertexA((SVertex*)((*e)->vertexA()->userdata)); + (*e)->setVertexB((SVertex*)((*e)->vertexB()->userdata)); + (*e)->setNextEdge((FEdge*)((*e)->nextEdge()->userdata)); + (*e)->setPreviousEdge((FEdge*)((*e)->previousEdge()->userdata)); + } + + + // reset all brothers userdata to NULL: + //------------------------------------- + //--------- + // vertices + //--------- + for(sv=_verticesList.begin(),svend=_verticesList.end(); + sv!=svend; + sv++) + { + (*sv)->userdata = NULL; + } + + //------ + // edges + //------ + for(e=_edgesList.begin(),eend=_edgesList.end(); + e!=eend; + e++) + { + (*e)->userdata = NULL; + } + } + /*! Cloning method. */ + virtual SShape * duplicate() + { + SShape *clone = new SShape(*this); + return clone; + } + /*! Destructor. */ + virtual inline ~SShape() + { + vector<SVertex*>::iterator sv,svend; + vector<FEdge*>::iterator e,eend; + if(0 != _verticesList.size()) + { + for(sv=_verticesList.begin(),svend=_verticesList.end(); + sv!=svend; + sv++) + { + delete (*sv); + } + _verticesList.clear(); + } + + if(0 != _edgesList.size()) + { + for(e=_edgesList.begin(),eend=_edgesList.end(); + e!=eend; + e++) + { + delete (*e); + } + _edgesList.clear(); + } + + //! Clear the chains list + //----------------------- + if(0 != _chains.size()) + { + _chains.clear(); + } + } + + /*! Adds a FEdge to the list of FEdges. */ + inline void AddEdge(FEdge *iEdge) + { + _edgesList.push_back(iEdge); + } + + /*! Adds a SVertex to the list of SVertex of this Shape. + * The SShape attribute of the SVertex is also set to 'this'. + */ + inline void AddNewVertex(SVertex* iv) {iv->setShape(this);_verticesList.push_back(iv);} + inline void AddChain(FEdge *iEdge){ + _chains.push_back(iEdge); + } + + inline SVertex * CreateSVertex(const Vec3r& P3D, const Vec3r& P2D, const Id& id) + { + SVertex *Ia = new SVertex(P3D, id); + Ia->setPoint2D(P2D); + AddNewVertex(Ia); + return Ia; + } + /* splits an edge into several edges. + * The edge's vertices are passed rather than + * the edge itself. This way, all feature edges (SILHOUETTE, + * CREASE, BORDER) are splitted in the same time. + * The processed edges are flagged as done (using the userdata + * flag).One single new vertex is created whereas + * several splitted edges might created for the different + * kinds of edges. These new elements are added to the lists + * maintained by the shape. + * new chains are also created. + * ioA + * The first vertex for the edge that gets splitted + * ioB + * The second vertex for the edge that gets splitted + * iParameters + * A vector containing 2D real vectors indicating the parameters + * giving the intersections coordinates in 3D and in 2D. + * These intersections points must be sorted from B to A. + * Each parameter defines the intersection point I as I=A+T*AB. + * T<0 and T>1 are then incorrect insofar as they give intersections + * points that lie outside the segment. + * ioNewEdges + * The edges that are newly created (the initial edges are not + * included) are added to this list. + */ + inline void SplitEdge(FEdge *fe, const vector<Vec2r>& iParameters, vector<FEdge*>& ioNewEdges) + { + + SVertex *ioA = fe->vertexA(); + SVertex *ioB = fe->vertexB(); + Vec3r A = ioA->point3D(); + Vec3r B = ioB->point3D(); + Vec3r a = ioA->point2D(); + Vec3r b = ioB->point2D(); + SVertex *svA, *svB; + + Vec3r newpoint3d,newpoint2d; + vector<SVertex*> intersections; + real t,T; + for(vector<Vec2r>::const_iterator p=iParameters.begin(),pend=iParameters.end(); + p!=pend; + p++) + { + T=(*p)[0]; + t=(*p)[1]; + + if((t < 0) || (t > 1)) + cerr << "Warning: Intersection out of range for edge " << ioA->getId() << " - " << ioB->getId() << endl; + + // compute the 3D and 2D coordinates for the intersections points: + newpoint3d = Vec3r(A + T*(B-A)); + newpoint2d = Vec3r(a + t*(b-a)); + + // create new SVertex: + // (we keep B's id) + SVertex* newVertex = new SVertex(newpoint3d, ioB->getId()); + newVertex->setPoint2D(newpoint2d); + + // Add this vertex to the intersections list: + intersections.push_back(newVertex); + + // Add this vertex to this sshape: + AddNewVertex(newVertex); + } + + for(vector<SVertex*>::iterator sv=intersections.begin(),svend=intersections.end(); + sv!=svend; + sv++) + { + svA = fe->vertexA(); + svB = fe->vertexB(); + + // We split edge AB into AA' and A'B. A' and A'B are created. + // AB becomes (address speaking) AA'. B is updated. + //-------------------------------------------------- + // The edge AB becomes edge AA'. + (fe)->setVertexB((*sv)); + // a new edge, A'B is created. + FEdge *newEdge; + if(fe->isSmooth()){ + newEdge = new FEdgeSmooth((*sv), svB); + FEdgeSmooth * se = dynamic_cast<FEdgeSmooth*>(newEdge); + FEdgeSmooth * fes = dynamic_cast<FEdgeSmooth*>(fe); + se->setFrsMaterialIndex(fes->frs_materialIndex()); + }else{ + newEdge = new FEdgeSharp((*sv), svB); + FEdgeSharp * se = dynamic_cast<FEdgeSharp*>(newEdge); + FEdgeSharp * fes = dynamic_cast<FEdgeSharp*>(fe); + se->setaFrsMaterialIndex(fes->aFrsMaterialIndex()); + se->setbFrsMaterialIndex(fes->bFrsMaterialIndex()); + } + + newEdge->setNature((fe)->getNature()); + + + // to build a new chain: + AddChain(newEdge); + // add the new edge to the sshape edges list. + AddEdge(newEdge); + // add new edge to the list of new edges passed as argument: + ioNewEdges.push_back(newEdge); + + // update edge A'B for the next pointing edge + newEdge->setNextEdge((fe)->nextEdge()); + fe->nextEdge()->setPreviousEdge(newEdge); + Id id(fe->getId().getFirst(), fe->getId().getSecond()+1); + newEdge->setId(fe->getId()); + fe->setId(id); + + // update edge AA' for the next pointing edge + //ioEdge->setNextEdge(newEdge); + (fe)->setNextEdge(NULL); + + // update vertex pointing edges list: + // -- vertex B -- + svB->Replace((fe), newEdge); + // -- vertex A' -- + (*sv)->AddFEdge((fe)); + (*sv)->AddFEdge(newEdge); + } + + } + + /* splits an edge into 2 edges. The new vertex and edge are added + * to the sshape list of vertices and edges + * a new chain is also created. + * returns the new edge. + * ioEdge + * The edge that gets splitted + * newpoint + * x,y,z coordinates of the new point. + */ + inline FEdge* SplitEdgeIn2(FEdge* ioEdge, SVertex * ioNewVertex) + { + //soc unused - SVertex *A = ioEdge->vertexA(); + SVertex *B = ioEdge->vertexB(); + + + // We split edge AB into AA' and A'B. A' and A'B are created. + // AB becomes (address speaking) AA'. B is updated. + //-------------------------------------------------- + + // a new edge, A'B is created. + FEdge *newEdge; + if(ioEdge->isSmooth()){ + newEdge = new FEdgeSmooth(ioNewVertex, B); + FEdgeSmooth * se = dynamic_cast<FEdgeSmooth*>(newEdge); + FEdgeSmooth * fes = dynamic_cast<FEdgeSmooth*>(ioEdge); + se->setFrsMaterialIndex(fes->frs_materialIndex()); + }else{ + newEdge = new FEdgeSharp(ioNewVertex, B); + FEdgeSharp * se = dynamic_cast<FEdgeSharp*>(newEdge); + FEdgeSharp * fes = dynamic_cast<FEdgeSharp*>(ioEdge); + se->setaFrsMaterialIndex(fes->aFrsMaterialIndex()); + se->setbFrsMaterialIndex(fes->bFrsMaterialIndex()); + } + newEdge->setNature(ioEdge->getNature()); + + + if(ioEdge->nextEdge() != 0) + ioEdge->nextEdge()->setPreviousEdge(newEdge); + + // update edge A'B for the next pointing edge + newEdge->setNextEdge(ioEdge->nextEdge()); + // update edge A'B for the previous pointing edge + newEdge->setPreviousEdge(0); // because it is now a TVertex + Id id(ioEdge->getId().getFirst(), ioEdge->getId().getSecond()+1); + newEdge->setId(ioEdge->getId()); + ioEdge->setId(id); + + // update edge AA' for the next pointing edge + ioEdge->setNextEdge(0); // because it is now a TVertex + + // update vertex pointing edges list: + // -- vertex B -- + B->Replace(ioEdge, newEdge); + // -- vertex A' -- + ioNewVertex->AddFEdge(ioEdge); + ioNewVertex->AddFEdge(newEdge); + + // to build a new chain: + AddChain(newEdge); + AddEdge(newEdge); // FIXME ?? + + // The edge AB becomes edge AA'. + ioEdge->setVertexB(ioNewVertex); + + if(ioEdge->isSmooth()){ + ((FEdgeSmooth*)newEdge)->setFace(((FEdgeSmooth*)ioEdge)->face()); + } + + return newEdge; + } + + /*! Sets the Bounding Box of the Shape */ + inline void setBBox(const BBox<Vec3r>& iBBox) {_BBox = iBBox;} + + /*! Compute the bbox of the sshape */ + inline void ComputeBBox() + { + if(0 == _verticesList.size()) + return; + + Vec3r firstVertex = _verticesList[0]->point3D(); + real XMax = firstVertex[0]; + real YMax = firstVertex[1]; + real ZMax = firstVertex[2]; + + real XMin = firstVertex[0]; + real YMin = firstVertex[1]; + real ZMin = firstVertex[2]; + + vector<SVertex*>::iterator v,vend; + // parse all the coordinates to find + // the Xmax, YMax, ZMax + for(v=_verticesList.begin(),vend=_verticesList.end(); + v!=vend; + v++) + { + Vec3r vertex = (*v)->point3D(); + // X + real x = vertex[0]; + if(x > XMax) + XMax = x; + if(x < XMin) + XMin = x; + + // Y + real y = vertex[1]; + if(y > YMax) + YMax = y; + if(y < YMin) + YMin = y; + + // Z + real z = vertex[2]; + if(z > ZMax) + ZMax = z; + if(z < ZMin) + ZMin = z; + } + + + setBBox(BBox<Vec3r>(Vec3r(XMin, YMin, ZMin), Vec3r(XMax, YMax, ZMax))); + } + + inline void RemoveEdgeFromChain(FEdge *iEdge) + { + for(vector<FEdge*>::iterator fe=_chains.begin(), feend=_chains.end(); + fe!=feend; + fe++) + { + if(iEdge == (*fe)) + { + _chains.erase(fe); + break; + } + } + } + + inline void RemoveEdge(FEdge *iEdge) + { + for(vector<FEdge*>::iterator fe=_edgesList.begin(), feend=_edgesList.end(); + fe!=feend; + fe++) + { + if(iEdge == (*fe)) + { + _edgesList.erase(fe); + break; + } + } + } + + /* accessors */ + /*! Returns the list of SVertex of the Shape. */ + inline vector<SVertex*>& getVertexList() {return _verticesList;} // Get vertices list + /*! Returns the list of FEdges of the Shape. */ + inline vector<FEdge*>& getEdgeList() {return _edgesList;} // Get edges list + inline vector<FEdge*>& getChains() {return _chains;} + /*! Returns the bounding box of the shape. */ + inline const BBox<Vec3r>& bbox() {return _BBox;} + /*! Returns the ith material of the shape. */ + inline const FrsMaterial& frs_material(unsigned i) const {return _FrsMaterials[i];} + /*! Returns the list of materials of the Shape. */ + inline const vector<FrsMaterial>& frs_materials() const {return _FrsMaterials;} + inline ViewShape * viewShape() {return _ViewShape;} + inline float importance() const {return _importance;} + /*! Returns the Id of the Shape. */ + inline Id getId() const { return _Id; } + + /* Modififers */ + /*! Sets the Id of the shape.*/ + inline void setId(Id id) {_Id = id;} + /*! Sets the list of materials for the shape */ + inline void setFrsMaterials(const vector<FrsMaterial>& iMaterials) {_FrsMaterials = iMaterials;} + inline void setViewShape(ViewShape *iShape) {_ViewShape = iShape;} + inline void setImportance(float importance){_importance = importance;} +}; + +#endif // SILHOUETTE_H diff --git a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp new file mode 100755 index 00000000000..c0817189bc2 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.cpp @@ -0,0 +1,266 @@ + +// +// 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 "Silhouette.h" +#include "SilhouetteGeomEngine.h" +#include "../geometry/GeomUtils.h" + +using namespace std; + +Vec3r SilhouetteGeomEngine::_Viewpoint = Vec3r(0,0,0); +real SilhouetteGeomEngine::_translation[3] = {0,0,0}; +real SilhouetteGeomEngine::_modelViewMatrix[4][4] = {{1,0,0,0}, + {0,1,0,0}, + {0,0,1,0}, + {0,0,0,1}}; +real SilhouetteGeomEngine::_projectionMatrix[4][4] = {{1,0,0,0}, + {0,1,0,0}, + {0,0,1,0}, + {0,0,0,1}}; +real SilhouetteGeomEngine::_transform[4][4] = {{1,0,0,0}, + {0,1,0,0}, + {0,0,1,0}, + {0,0,0,1}}; +int SilhouetteGeomEngine::_viewport[4] = {1,1,1,1}; // the viewport +real SilhouetteGeomEngine::_Focal = 0.0; + +real SilhouetteGeomEngine::_glProjectionMatrix[4][4] = {{1,0,0,0}, + {0,1,0,0}, + {0,0,1,0}, + {0,0,0,1}}; +real SilhouetteGeomEngine::_glModelViewMatrix[4][4] = {{1,0,0,0}, + {0,1,0,0}, + {0,0,1,0}, + {0,0,0,1}}; +real SilhouetteGeomEngine::_znear = 0.0; +real SilhouetteGeomEngine::_zfar = 100.0; +bool SilhouetteGeomEngine::_isOrthographicProjection = false; + +SilhouetteGeomEngine * SilhouetteGeomEngine::_pInstance = 0; + +void SilhouetteGeomEngine::setTransform(const real iModelViewMatrix[4][4], const real iProjectionMatrix[4][4], const int iViewport[4], real iFocal) +{ + unsigned int i,j; + _translation[0] = iModelViewMatrix[3][0]; + _translation[1] = iModelViewMatrix[3][1]; + _translation[2] = iModelViewMatrix[3][2]; + + for(i=0; i<4; i++){ + for(j=0; j<4; j++) + { + _modelViewMatrix[i][j] = iModelViewMatrix[j][i]; + _glModelViewMatrix[i][j] = iModelViewMatrix[i][j]; + } + } + + for(i=0; i<4; i++){ + for(j=0; j<4; j++) + { + _projectionMatrix[i][j] = iProjectionMatrix[j][i]; + _glProjectionMatrix[i][j] = iProjectionMatrix[i][j]; + } + } + + for(i=0; i<4; i++){ + for(j=0; j<4; j++) + { + _transform[i][j] = 0; + for(unsigned int k=0; k<4; k++) + _transform[i][j] += _projectionMatrix[i][k] * _modelViewMatrix[k][j]; + } + } + + for(i=0; i<4; i++){ + _viewport[i] = iViewport[i]; + } + _Focal = iFocal; + + _isOrthographicProjection = (iProjectionMatrix[3][3] != 0.0); +} + +void SilhouetteGeomEngine::setFrustum(real iZNear, real iZFar) +{ + _znear = iZNear; + _zfar = iZFar; +} + +void SilhouetteGeomEngine::retrieveViewport(int viewport[4]){ + memcpy(viewport, _viewport, 4*sizeof(int)); +} +//#define HUGE 1e9 + +void SilhouetteGeomEngine::ProjectSilhouette(vector<SVertex*>& ioVertices) +{ + Vec3r newPoint; + // real min=HUGE; + // real max=-HUGE; + vector<SVertex*>::iterator sv, svend; + + for(sv=ioVertices.begin(), svend=ioVertices.end(); + sv!=svend; + sv++) + { + GeomUtils::fromWorldToImage((*sv)->point3D(), newPoint, _modelViewMatrix, _projectionMatrix, _viewport); + newPoint[2] = (-newPoint[2]-_znear)/(_zfar-_znear); // normalize Z between 0 and 1 + (*sv)->setPoint2D(newPoint); + //cerr << (*sv)->point2d().z() << " "; + // real d=(*sv)->point2d()[2]; + // if (d>max) max =d; + // if (d<min) min =d; + } + // for(sv=ioVertices.begin(), svend=ioVertices.end(); + // sv!=svend; + // sv++) + // { + // Vec3r P((*sv)->point2d()); + // (*sv)->setPoint2D(Vec3r(P[0], P[1], 1.0-(P[2]-min)/(max-min))); + // //cerr<<(*sv)->point2d()[2]<<" "; + // } +} + +void SilhouetteGeomEngine::ProjectSilhouette(SVertex* ioVertex) +{ + Vec3r newPoint; + // real min=HUGE; + // real max=-HUGE; + vector<SVertex*>::iterator sv, svend; + GeomUtils::fromWorldToImage(ioVertex->point3D(), newPoint, _modelViewMatrix, _projectionMatrix, _viewport); + newPoint[2] = (-newPoint[2]-_znear)/(_zfar-_znear); // normalize Z between 0 and 1 + ioVertex->setPoint2D(newPoint); +} + +real SilhouetteGeomEngine::ImageToWorldParameter(FEdge *fe, real t) +{ + if( _isOrthographicProjection ) + return t; + + // we need to compute for each parameter t the corresponding + // parameter T which gives the intersection in 3D. + real T; + + // suffix w for world, c for camera, r for retina, i for image + Vec3r Aw = (fe)->vertexA()->point3D(); + Vec3r Bw = (fe)->vertexB()->point3D(); + Vec3r Ac, Bc; + GeomUtils::fromWorldToCamera(Aw, Ac, _modelViewMatrix); + GeomUtils::fromWorldToCamera(Bw, Bc, _modelViewMatrix); + Vec3r ABc = Bc - Ac; +#if 0 + cout << "Ac " << Ac << endl; + cout << "Bc " << Bc << endl; + cout << "ABc " << ABc << endl; +#endif + Vec3r Ai = (fe)->vertexA()->point2D(); + Vec3r Bi = (fe)->vertexB()->point2D(); + Vec3r Ii = Ai + t * (Bi - Ai); // the intersection point in the 2D image space + Vec3r Ir, Ic; + GeomUtils::fromImageToRetina(Ii, Ir, _viewport); + + real alpha, beta, denom; + real m11 = _projectionMatrix[0][0]; + real m13 = _projectionMatrix[0][2]; + real m22 = _projectionMatrix[1][1]; + real m23 = _projectionMatrix[1][2]; + + if (fabs(ABc[0]) > 1e-6) { + + alpha = ABc[2] / ABc[0]; + beta = Ac[2] - alpha * Ac[0]; + denom = alpha * (Ir[0] + m13) + m11; + if (fabs(denom) < 1e-6) + goto iter; + Ic[0] = -beta * (Ir[0] + m13) / denom; +// Ic[1] = -(Ir[1] + m23) * (alpha * Ic[0] + beta) / m22; +// Ic[2] = alpha * (Ic[0] - Ac[0]) + Ac[2]; + T = (Ic[0] - Ac[0]) / ABc[0]; + + } else if (fabs(ABc[1]) > 1e-6) { + + alpha = ABc[2] / ABc[1]; + beta = Ac[2] - alpha * Ac[1]; + denom = alpha * (Ir[1] + m23) + m22; + if (fabs(denom) < 1e-6) + goto iter; + Ic[1] = -beta * (Ir[1] + m23) / denom; +// Ic[0] = -(Ir[0] + m13) * (alpha * Ic[1] + beta) / m11; +// Ic[2] = alpha * (Ic[1] - Ac[1]) + Ac[2]; + T = (Ic[1] - Ac[1]) / ABc[1]; + + } else { + +iter: bool x_coords, less_than; + if (fabs(Bi[0] - Ai[0]) > 1e-6) { + x_coords = true; + less_than = Ai[0] < Bi[0]; + } else { + x_coords = false; + less_than = Ai[1] < Bi[1]; + } + Vec3r Pc, Pr, Pi; + real T_sta = 0.0; + real T_end = 1.0; + real delta_x, delta_y, dist, dist_threshold = 1e-6; + int i, max_iters = 100; + for (i = 0; i < max_iters; i++) { + T = T_sta + 0.5 * (T_end - T_sta); + Pc = Ac + T * ABc; + GeomUtils::fromCameraToRetina(Pc, Pr, _projectionMatrix); + GeomUtils::fromRetinaToImage(Pr, Pi, _viewport); + delta_x = Ii[0] - Pi[0]; + delta_y = Ii[1] - Pi[1]; + dist = sqrt(delta_x * delta_x + delta_y * delta_y); + if (dist < dist_threshold) + break; + if (x_coords) { + if (less_than) { + if (Pi[0] < Ii[0]) { T_sta = T; } else { T_end = T; } + } else { + if (Pi[0] > Ii[0]) { T_sta = T; } else { T_end = T; } + } + } else { + if (less_than) { + if (Pi[1] < Ii[1]) { T_sta = T; } else { T_end = T; } + } else { + if (Pi[1] > Ii[1]) { T_sta = T; } else { T_end = T; } + } + } + } +#if 0 + printf("SilhouetteGeomEngine::ImageToWorldParameter(): #iters = %d, dist = %e\n", i, dist); +#endif + if (i == max_iters) + printf("SilhouetteGeomEngine::ImageToWorldParameter(): reached to max_iters (dist = %e)\n", dist); + } + + return T; +} + +Vec3r SilhouetteGeomEngine::WorldToImage(const Vec3r& M) + +{ + + Vec3r newPoint; + GeomUtils::fromWorldToImage(M, newPoint, _transform, _viewport); + newPoint[2] = (-newPoint[2]-_znear)/(_zfar-_znear); // normalize Z between 0 and 1 + return newPoint; + +} + diff --git a/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h new file mode 100755 index 00000000000..5bd89f8a162 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/SilhouetteGeomEngine.h @@ -0,0 +1,123 @@ +// +// Filename : SilhouetteGeomEngine.h +// Author(s) : Stephane Grabli +// Purpose : Class to perform all geometric operations dedicated +// to silhouette. That, for example, implies that +// this geom engine has as member data the viewpoint, +// transformations, projections... +// Date of creation : 03/09/2002 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef SILHOUETTEGEOMENGINE_H +# define SILHOUETTEGEOMENGINE_H + +# include <vector> +# include "../system/FreestyleConfig.h" +# include "../geometry/Geom.h" + +using namespace Geometry; + +class SVertex; +class FEdge; + +class LIB_VIEW_MAP_EXPORT SilhouetteGeomEngine +{ +private: + static Vec3r _Viewpoint; // The viewpoint under which the silhouette has to be computed + static real _translation[3]; + static real _modelViewMatrix[4][4]; // the model view matrix (_modelViewMatrix[i][j] means element of line i and column j) + static real _projectionMatrix[4][4]; // the projection matrix (_projectionMatrix[i][j] means element of line i and column j) + static real _transform[4][4]; // the global transformation from world to screen (projection included) (_transform[i][j] means element of line i and column j) + static int _viewport[4]; // the viewport + static real _Focal; + + static real _znear; + static real _zfar; + + static real _glProjectionMatrix[4][4]; // GL style (column major) projection matrix + static real _glModelViewMatrix[4][4]; // GL style (column major) model view matrix + +static bool _isOrthographicProjection; + + + static SilhouetteGeomEngine *_pInstance; +public: + + /*! retrieves an instance on the singleton */ + static SilhouetteGeomEngine * getInstance() + { + if(0 == _pInstance) + { + _pInstance = new SilhouetteGeomEngine; + } + return _pInstance; + } + + /*! Sets the current viewpoint */ + static inline void setViewpoint(const Vec3r& ivp) {_Viewpoint = ivp;} + + /*! Sets the current transformation + * iModelViewMatrix + * The 4x4 model view matrix, in column major order (openGL like). + * iProjection matrix + * The 4x4 projection matrix, in column major order (openGL like). + * iViewport + * The viewport. 4 real array: origin.x, origin.y, width, length + * iFocal + * The focal length + */ + static void setTransform(const real iModelViewMatrix[4][4], const real iProjectionMatrix[4][4], const int iViewport[4], real iFocal) ; + + /*! Sets the current znear and zfar + */ + static void setFrustum(real iZNear, real iZFar) ; + + /* accessors */ + static void retrieveViewport(int viewport[4]); + + /*! Projects the silhouette in camera coordinates + * This method modifies the ioEdges passed as argument. + * ioVertices + * The vertices to project. It is modified during the + * operation. + */ + static void ProjectSilhouette(std::vector<SVertex*>& ioVertices); + static void ProjectSilhouette(SVertex* ioVertex); + + /*! transforms the parameter t defining a 2D intersection for edge fe in order to obtain + * the parameter giving the corresponding 3D intersection. + * Returns the 3D parameter + * fe + * The edge + * t + * The parameter for the 2D intersection. + */ + static real ImageToWorldParameter(FEdge *fe, real t); + + /*! From world to image */ + static Vec3r WorldToImage(const Vec3r& M); +}; + +#endif // SILHOUETTEGEOMENGINE_H diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp new file mode 100755 index 00000000000..4c179d9ff02 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.cpp @@ -0,0 +1,267 @@ +// +// 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 "Silhouette.h" +#include "SteerableViewMap.h" +#include "../image/ImagePyramid.h" +#include "../image/Image.h" +#include <math.h> +#include "../geometry/Geom.h" +using namespace Geometry; + +//soc #include <qstring.h> +//soc #include <qimage.h> +#include <sstream> + +extern "C" { +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" +} + +SteerableViewMap::SteerableViewMap(unsigned int nbOrientations){ + _nbOrientations = nbOrientations; + _bound = cos(M_PI/(float)_nbOrientations); + for(unsigned i=0; i<_nbOrientations; ++i){ + _directions.push_back(Vec2d(cos((float)i*M_PI/(float)_nbOrientations), sin((float)i*M_PI/(float)_nbOrientations))); + } + Build(); +} + +void SteerableViewMap::Build(){ + _imagesPyramids = new ImagePyramid*[_nbOrientations+1]; // one more map to store the complete visible VM + memset((_imagesPyramids),0,(_nbOrientations+1)*sizeof(ImagePyramid*)); +} + +SteerableViewMap::SteerableViewMap(const SteerableViewMap& iBrother){ + _nbOrientations = iBrother._nbOrientations; + unsigned i; + _bound = iBrother._bound; + _directions = iBrother._directions; + _mapping = iBrother._mapping; + _imagesPyramids = new ImagePyramid*[_nbOrientations+1]; // one more map to store the complete visible VM + for(i=0;i<_nbOrientations+1;++i) + _imagesPyramids[i] = new GaussianPyramid(*(dynamic_cast<GaussianPyramid*>(iBrother._imagesPyramids[i]))); +} + +SteerableViewMap::~SteerableViewMap(){ + Clear(); +} + +void SteerableViewMap::Clear(){ + unsigned i; + if(_imagesPyramids){ + for(i=0; i<=_nbOrientations; ++i){ + if(_imagesPyramids[i]) + delete (_imagesPyramids)[i]; + } + delete [] _imagesPyramids; + _imagesPyramids = 0; + } + if(!_mapping.empty()){ + for(map<unsigned int, double*>::iterator m=_mapping.begin(), mend=_mapping.end(); + m!=mend; + ++m){ + delete [] (*m).second; + } + _mapping.clear(); + } +} + +void SteerableViewMap::Reset(){ + Clear(); + Build(); +} + +double SteerableViewMap::ComputeWeight(const Vec2d& dir, unsigned i){ + double dotp = fabs(dir*_directions[i]); + if(dotp < _bound) + return 0; + if(dotp>1) + dotp = 1; + + return cos((float)_nbOrientations/2.0*acos(dotp)); +} + +double * SteerableViewMap::AddFEdge(FEdge *iFEdge){ + unsigned i; + unsigned id = iFEdge->getId().getFirst(); + map<unsigned int, double* >::iterator o = _mapping.find(id); + if(o!=_mapping.end()){ + return (*o).second; + } + double * res = new double[_nbOrientations]; + for(i=0; i<_nbOrientations; ++i){ + res[i] = 0; + } + Vec3r o2d3 = iFEdge->orientation2d(); + Vec2r o2d2(o2d3.x(), o2d3.y()); + real norm = o2d2.norm(); + if(norm < 1e-6){ + return res; + } + o2d2/=norm; + + for(i=0; i<_nbOrientations; ++i){ + res[i] = ComputeWeight(o2d2, i); + } + _mapping[id] = res; + return res; +} + +unsigned SteerableViewMap::getSVMNumber(const Vec2f& orient){ + Vec2f dir(orient); + //soc unsigned res = 0; + real norm = dir.norm(); + if(norm < 1e-6){ + return _nbOrientations+1; + } + dir/=norm; + double maxw = 0.f; + unsigned winner = _nbOrientations+1; + for(unsigned i=0; i<_nbOrientations; ++i){ + double w = ComputeWeight(dir, i); + if(w>maxw){ + maxw = w; + winner = i; + } + } + return winner; +} + + +unsigned SteerableViewMap::getSVMNumber(unsigned id){ + map<unsigned int, double* >::iterator o = _mapping.find(id); + if(o!=_mapping.end()){ + double* wvalues= (*o).second; + double maxw = 0.f; + unsigned winner = _nbOrientations+1; + for(unsigned i=0; i<_nbOrientations; ++i){ + double w = wvalues[i]; + if(w>maxw){ + maxw = w; + winner = i; + } + } + return winner; + } + return _nbOrientations+1; +} + +void SteerableViewMap::buildImagesPyramids(GrayImage **steerableBases, bool copy, unsigned iNbLevels, float iSigma){ + for(unsigned i=0; i<=_nbOrientations; ++i){ + ImagePyramid * svm = (_imagesPyramids)[i]; + if(svm) + delete svm; + if(copy) + svm = new GaussianPyramid(*(steerableBases[i]), iNbLevels, iSigma); + else + svm = new GaussianPyramid(steerableBases[i], iNbLevels, iSigma); + _imagesPyramids[i] = svm; + } +} + +float SteerableViewMap::readSteerableViewMapPixel(unsigned iOrientation, int iLevel, int x, int y){ + ImagePyramid *pyramid = _imagesPyramids[iOrientation]; + if(pyramid==0){ + cout << "Warning: this steerable ViewMap level doesn't exist" << endl; + return 0; + } + if((x<0) || (x>=pyramid->width()) || (y<0) || (y>=pyramid->height())) + return 0; + //float v = pyramid->pixel(x,pyramid->height()-1-y,iLevel)*255.f; + float v = pyramid->pixel(x,pyramid->height()-1-y,iLevel)/32.f; // we encode both the directionality and the lines counting on 8 bits + // (because of frame buffer). Thus, we allow until 8 lines to pass through + // the same pixel, so that we can discretize the Pi/_nbOrientations angle into + // 32 slices. Therefore, for example, in the vertical direction, a vertical line + // will have the value 32 on each pixel it passes through. + return v; +} + +float SteerableViewMap::readCompleteViewMapPixel(int iLevel, int x, int y){ + return readSteerableViewMapPixel(_nbOrientations,iLevel,x,y); +} + +unsigned int SteerableViewMap::getNumberOfPyramidLevels() const{ + if(_imagesPyramids[0]) + return _imagesPyramids[0]->getNumberOfLevels(); + return 0; +} + +void SteerableViewMap::saveSteerableViewMap() const { + for(unsigned i=0; i<=_nbOrientations; ++i){ + if(_imagesPyramids[i] == 0){ + cerr << "SteerableViewMap warning: orientation " << i <<" of steerable View Map whas not been computed yet" << endl; + continue; + } + int ow = _imagesPyramids[i]->width(0); + int oh = _imagesPyramids[i]->height(0); + + //soc QString base("SteerableViewMap"); + string base("SteerableViewMap"); + stringstream filename; + + for(int j=0; j<_imagesPyramids[i]->getNumberOfLevels(); ++j){ //soc + float coeff = 1;//1/255.f; //100*255;//*pow(2,j); + //soc QImage qtmp(ow, oh, QImage::Format_RGB32); + ImBuf *ibuf = IMB_allocImBuf(ow, oh, 32, IB_rect, 0); + int rowbytes = ow*4; + char *pix; + + for(int y=0;y<oh;++y){ //soc + for(int x=0;x<ow;++x){ //soc + int c = (int)(coeff*_imagesPyramids[i]->pixel(x,y,j)); + if(c>255) + c=255; + //int c = (int)(_imagesPyramids[i]->pixel(x,y,j)); + + //soc qtmp.setPixel(x,y,qRgb(c,c,c)); + pix = (char*)ibuf->rect + y*rowbytes + x*4; + pix[0] = pix [1] = pix[2] = c; + } + } + + //soc qtmp.save(base+QString::number(i)+"-"+QString::number(j)+".png", "PNG"); + filename << base; + filename << i << "-" << j << ".png"; + ibuf->ftype= PNG; + IMB_saveiff(ibuf, const_cast<char *>(filename.str().c_str()), IB_rect); + + } + // QString base("SteerableViewMap"); + // for(unsigned j=0; j<_imagesPyramids[i]->getNumberOfLevels(); ++j){ + // GrayImage * img = _imagesPyramids[i]->getLevel(j); + // int ow = img->width(); + // int oh = img->height(); + // float coeff = 1; //100*255;//*pow(2,j); + // QImage qtmp(ow, oh, 32); + // for(unsigned y=0;y<oh;++y){ + // for(unsigned x=0;x<ow;++x){ + // int c = (int)(coeff*img->pixel(x,y)); + // if(c>255) + // c=255; + // //int c = (int)(_imagesPyramids[i]->pixel(x,y,j)); + // qtmp.setPixel(x,y,qRgb(c,c,c)); + // } + // } + // qtmp.save(base+QString::number(i)+"-"+QString::number(j)+".png", "PNG"); + // } + // + } +} diff --git a/source/blender/freestyle/intern/view_map/SteerableViewMap.h b/source/blender/freestyle/intern/view_map/SteerableViewMap.h new file mode 100755 index 00000000000..fe7c2493752 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/SteerableViewMap.h @@ -0,0 +1,153 @@ +// +// Filename : SteerbaleViewMap.h +// Author(s) : Stephane Grabli +// Purpose : Convenient access to the steerable ViewMap +// to which any element of the ViewMap belongs to. +// Date of creation : 01/07/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// +#ifndef STEERABLEVIEWMAP_H +# define STEERABLEVIEWMAP_H + +#include <map> +#include "../system/FreestyleConfig.h" +#include "../geometry/Geom.h" +using namespace Geometry; + +using namespace std; + +class FEdge; +class ImagePyramid; +class GrayImage; +/*! This class checks for every FEdge in which steerable + * it belongs and stores the mapping allowing to retrieve + * this information from the FEdge Id + */ +class LIB_VIEW_MAP_EXPORT SteerableViewMap{ +protected: + map<unsigned int, double* > _mapping; // for each vector the list of nbOrientations weigths corresponding to its contributions to the nbOrientations directional maps + unsigned _nbOrientations; + ImagePyramid **_imagesPyramids; // the pyramids of images storing the different SVM + + // internal + double _bound; // cos(Pi/N) + vector<Vec2d> _directions; + +public: + SteerableViewMap(unsigned int nbOrientations = 4); + SteerableViewMap(const SteerableViewMap& iBrother); + virtual ~SteerableViewMap(); + + /*! Resets everything */ + virtual void Reset(); + + /*! Adds a FEdge to steerable VM. + * Returns the nbOrientations weigths corresponding to + * the FEdge contributions to the nbOrientations directional maps. + */ + double* AddFEdge(FEdge *iFEdge); + + /*! Compute the weight of direction dir for orientation iNOrientation */ + double ComputeWeight(const Vec2d& dir, unsigned iNOrientation); + + /*! Returns the number of the SVM to which a direction belongs + * to. + * \param dir + * The direction + */ + unsigned getSVMNumber(const Vec2f& dir); + + /*! Returns the number of the SVM to which a FEdge belongs + * most. + * \param id + * The First element of the Id struct of the FEdge + * we're intersted in. + */ + unsigned getSVMNumber(unsigned id); + + /*! Builds _nbOrientations+1 pyramids of images from the _nbOrientations+1 base images + * of the steerable viewmap. + * \param steerableBases + * The _nbOrientations+1 images constituing the basis for the steerable + * pyramid. + * \param copy + * If false, the data is not duplicated, and Canvas deals + * with the memory management of these _nbOrientations+1 images. If true, data + * is copied, and it's up to the caller to delete the images. + * \params iNbLevels + * The number of levels desired for each pyramid. + * If iNbLevels == 0, the complete pyramid is built. + * \param iSigma + * The sigma that will be used for the gaussian blur + */ + void buildImagesPyramids(GrayImage **steerableBases, bool copy = false, unsigned iNbLevels=4, float iSigma = 1.f); + + /*! Reads a pixel value in one of the VewMap density steerable pyramids. + * Returns a value between 0 and 1. + * \param iOrientation + * the number telling which orientation we need to check. + * There are _nbOrientations+1 oriented ViewMaps: + * 0 -> the ViewMap containing every horizontal lines + * 1 -> the ViewMap containing every lines whose orientation is around PI/4 + * 2 -> the ViewMap containing every vertical lines + * 3 -> the ViewMap containing every lines whose orientation is around 3PI/4 + * 4 -> the complete ViewMap + * \param iLevel + * The level of the pyramid we want to read + * \param x + * The abscissa of the desired pixel specified in level0 coordinate + * system. The origin is the lower left corner. + * \param y + * The ordinate of the desired pixel specified in level0 coordinate + * system. The origin is the lower left corner. + */ + float readSteerableViewMapPixel(unsigned iOrientation, int iLevel, int x, int y); + + /*! Reads a pixel in the one of the level of the + * pyramid containing the images of the complete + * ViewMap. + * Returns a value between 0 and 1. + * Equivalent to : readSteerableViewMapPixel(nbOrientations, x,y) + */ + float readCompleteViewMapPixel(int iLevel, int x, int y); + + /*! Returns the number of levels in the pyramids */ + unsigned int getNumberOfPyramidLevels() const; + + /*! Returns the number of orientations */ + unsigned int getNumberOfOrientations() const{ + return _nbOrientations; + } + + /*! for debug purposes */ + void saveSteerableViewMap() const ; + +protected: + void Clear(); + void Build(); + + +}; + +#endif // STEERABLEVIEWMAP_H diff --git a/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp new file mode 100755 index 00000000000..3e0979f684f --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.cpp @@ -0,0 +1,666 @@ +// +// 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 "ViewMap.h" +#include "ViewEdgeXBuilder.h" +#include "../winged_edge/WXEdge.h" +#include "SilhouetteGeomEngine.h" +#include <list> + +using namespace std; + +void ViewEdgeXBuilder::Init(ViewShape *oVShape){ + if(0 == oVShape) + return; + + // for design conveniance, we store the current SShape. + _pCurrentSShape = oVShape->sshape(); + if(0 == _pCurrentSShape) + return; + + _pCurrentVShape = oVShape; + + // Reset previous data + //-------------------- + if(!_SVertexMap.empty()) + _SVertexMap.clear(); +} + +void ViewEdgeXBuilder::BuildViewEdges( WXShape *iWShape, ViewShape *oVShape, + vector<ViewEdge*>& ioVEdges, + vector<ViewVertex*>& ioVVertices, + vector<FEdge*>& ioFEdges, + vector<SVertex*>& ioSVertices){ + // Reinit structures + Init(oVShape); + + ViewEdge *vedge ; + // Let us build the smooth stuff + //---------------------------------------- + // We parse all faces to find the ones + // that contain smooth edges + vector<WFace*>& wfaces = iWShape->GetFaceList(); + vector<WFace*>::iterator wf, wfend; + WXFace *wxf; + for(wf=wfaces.begin(), wfend=wfaces.end(); + wf!=wfend; + wf++){ + wxf = dynamic_cast<WXFace*>(*wf); + if(false == ((wxf))->hasSmoothEdges()) // does it contain at least one smooth edge ? + continue; + // parse all smooth layers: + vector<WXFaceLayer*>& smoothLayers = wxf->getSmoothLayers(); + for(vector<WXFaceLayer*>::iterator sl = smoothLayers.begin(), slend=smoothLayers.end(); + sl!=slend; + ++sl){ + if(!(*sl)->hasSmoothEdge()) + continue; + if(stopSmoothViewEdge((*sl))) // has it been parsed already ? + continue; + // here we know that we're dealing with a face layer that has not been + // processed yet and that contains a smooth edge. + vedge = BuildSmoothViewEdge(OWXFaceLayer(*sl, true)); + } + } + + // Now let's build sharp view edges: + //---------------------------------- + // Reset all userdata for WXEdge structure + //---------------------------------------- + //iWShape->ResetUserData(); + + WXEdge * wxe; + vector<WEdge*>& wedges = iWShape->getEdgeList(); + // + //------------------------------ + for(vector<WEdge*>::iterator we=wedges.begin(),weend=wedges.end(); + we!=weend; + we++){ + wxe = dynamic_cast<WXEdge*>(*we); + if(Nature::NO_FEATURE == wxe->nature()) + continue; + + if(!stopSharpViewEdge(wxe)){ + bool b=true; + if(wxe->order() == -1) + b = false; + BuildSharpViewEdge(OWXEdge(wxe,b)); + } + } + + // Reset all userdata for WXEdge structure + //---------------------------------------- + iWShape->ResetUserData(); + + // Add all these new edges to the scene's feature edges list: + //----------------------------------------------------------- + vector<FEdge*>& newedges = _pCurrentSShape->getEdgeList(); + vector<SVertex*>& newVertices = _pCurrentSShape->getVertexList(); + vector<ViewVertex*>& newVVertices = _pCurrentVShape->vertices(); + vector<ViewEdge*>& newVEdges = _pCurrentVShape->edges(); + + // inserts in ioFEdges, at its end, all the edges of newedges + ioFEdges.insert(ioFEdges.end(), newedges.begin(), newedges.end()); + ioSVertices.insert(ioSVertices.end(), newVertices.begin(), newVertices.end()); + ioVVertices.insert(ioVVertices.end(), newVVertices.begin(), newVVertices.end()); + ioVEdges.insert(ioVEdges.end(), newVEdges.begin(), newVEdges.end()); + +} + +ViewEdge * ViewEdgeXBuilder::BuildSmoothViewEdge(const OWXFaceLayer& iFaceLayer){ + // Find first edge: + OWXFaceLayer first = iFaceLayer; + OWXFaceLayer currentFace = first; + + // bidirectional chaining. + // first direction + list<OWXFaceLayer> facesChain; + unsigned size = 0; + while(!stopSmoothViewEdge(currentFace.fl)){ + facesChain.push_back(currentFace); + ++size; + currentFace.fl->userdata = (void*)1; // processed + // Find the next edge! + currentFace = FindNextFaceLayer(currentFace); + } + OWXFaceLayer end = facesChain.back(); + // second direction + currentFace = FindPreviousFaceLayer(first); + while(!stopSmoothViewEdge(currentFace.fl)){ + facesChain.push_front(currentFace); + ++size; + currentFace.fl->userdata = (void*)1; // processed + // Find the previous edge! + currentFace = FindPreviousFaceLayer(currentFace); + } + first = facesChain.front(); + + if(iFaceLayer.fl->nature() & Nature::RIDGE){ + if(size<4){ + return 0; + } + } + + // Start a new chain edges + ViewEdge * newVEdge = new ViewEdge; + newVEdge->setId(_currentViewId); + ++_currentViewId; + + _pCurrentVShape->AddEdge(newVEdge); + + + // build FEdges + FEdge * feprevious = 0; + FEdge * fefirst = 0; + FEdge * fe = 0; + for(list<OWXFaceLayer>::iterator fl = facesChain.begin(), flend=facesChain.end(); + fl!=flend; + ++fl){ + fe = BuildSmoothFEdge(feprevious, (*fl)); + fe->setViewEdge(newVEdge); + if(!fefirst) + fefirst = fe; + feprevious = fe; + } + // Store the chain starting edge: + _pCurrentSShape->AddChain(fefirst); + newVEdge->setNature(iFaceLayer.fl->nature()); + newVEdge->setFEdgeA(fefirst); + newVEdge->setFEdgeB(fe); + + // is it a closed loop ? + if((first == end) && (size != 1)){ + fefirst->setPreviousEdge(fe); + fe->setNextEdge(fefirst); + newVEdge->setA(0); + newVEdge->setB(0); + }else{ + ViewVertex *vva = MakeViewVertex(fefirst->vertexA()); + ViewVertex *vvb = MakeViewVertex(fe->vertexB()); + + ((NonTVertex*)vva)->AddOutgoingViewEdge(newVEdge); + ((NonTVertex*)vvb)->AddIncomingViewEdge(newVEdge); + + newVEdge->setA(vva); + newVEdge->setB(vvb); + } + + return newVEdge; +} + +ViewEdge * ViewEdgeXBuilder::BuildSharpViewEdge(const OWXEdge& iWEdge) { + // Start a new sharp chain edges + ViewEdge * newVEdge = new ViewEdge; + newVEdge->setId(_currentViewId); + ++_currentViewId; + unsigned size=0; + + _pCurrentVShape->AddEdge(newVEdge); + + // Find first edge: + OWXEdge firstWEdge = iWEdge; + OWXEdge previousWEdge = firstWEdge; + OWXEdge currentWEdge = firstWEdge; + list<OWXEdge> edgesChain; + // bidirectional chaining + // first direction: + while(!stopSharpViewEdge(currentWEdge.e)){ + edgesChain.push_back(currentWEdge); + ++size; + currentWEdge.e->userdata = (void*)1; // processed + // Find the next edge! + currentWEdge = FindNextWEdge(currentWEdge); + } + OWXEdge endWEdge = edgesChain.back(); + // second direction + currentWEdge = FindPreviousWEdge(firstWEdge); + while(!stopSharpViewEdge(currentWEdge.e)){ + edgesChain.push_front(currentWEdge); + ++size; + currentWEdge.e->userdata = (void*)1; // processed + // Find the previous edge! + currentWEdge = FindPreviousWEdge(currentWEdge); + } + firstWEdge = edgesChain.front(); + + // build FEdges + FEdge * feprevious = 0; + FEdge * fefirst = 0; + FEdge * fe = 0; + for(list<OWXEdge>::iterator we = edgesChain.begin(), weend=edgesChain.end(); + we!=weend; + ++we){ + fe = BuildSharpFEdge(feprevious, (*we)); + fe->setViewEdge(newVEdge); + if(!fefirst) + fefirst = fe; + feprevious = fe; + } + // Store the chain starting edge: + _pCurrentSShape->AddChain(fefirst); + newVEdge->setNature(iWEdge.e->nature()); + newVEdge->setFEdgeA(fefirst); + newVEdge->setFEdgeB(fe); + + // is it a closed loop ? + if((firstWEdge == endWEdge) && (size!=1)){ + fefirst->setPreviousEdge(fe); + fe->setNextEdge(fefirst); + newVEdge->setA(0); + newVEdge->setB(0); + }else{ + ViewVertex *vva = MakeViewVertex(fefirst->vertexA()); + ViewVertex *vvb = MakeViewVertex(fe->vertexB()); + + ((NonTVertex*)vva)->AddOutgoingViewEdge(newVEdge); + ((NonTVertex*)vvb)->AddIncomingViewEdge(newVEdge); + + newVEdge->setA(vva); + newVEdge->setB(vvb); + } + + return newVEdge; +} + +OWXFaceLayer ViewEdgeXBuilder::FindNextFaceLayer(const OWXFaceLayer& iFaceLayer){ + WXFace *nextFace = 0; + WOEdge * woeend; + real tend; + if(iFaceLayer.order){ + woeend = iFaceLayer.fl->getSmoothEdge()->woeb(); + tend = iFaceLayer.fl->getSmoothEdge()->tb(); + }else{ + woeend = iFaceLayer.fl->getSmoothEdge()->woea(); + tend = iFaceLayer.fl->getSmoothEdge()->ta(); + } + // special case of EDGE_VERTEX config: + if((tend == 0.0) || (tend == 1.0)){ + WVertex *nextVertex; + if(tend == 0.0) + nextVertex = woeend->GetaVertex(); + else + nextVertex = woeend->GetbVertex(); + if(nextVertex->isBoundary()) // if it's a non-manifold vertex -> ignore + return OWXFaceLayer(0,true); + bool found = false; + WVertex::face_iterator f=nextVertex->faces_begin(); + WVertex::face_iterator fend=nextVertex->faces_end(); + while((!found) && (f!=fend)){ + nextFace = dynamic_cast<WXFace*>(*f); + if((0 != nextFace) && (nextFace!=iFaceLayer.fl->getFace())){ + vector<WXFaceLayer*> sameNatureLayers; + nextFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers); + if(sameNatureLayers.size() == 1) {// don't know + // maybe should test whether this face has + // also a vertex_edge configuration + WXFaceLayer * winner = sameNatureLayers[0]; + if(woeend == winner->getSmoothEdge()->woea()->twin()) + return OWXFaceLayer(winner,true); + else + return OWXFaceLayer(winner,false); + } + } + ++f; + } + }else{ + nextFace = dynamic_cast<WXFace*>(iFaceLayer.fl->getFace()->GetBordingFace(woeend)); + if(0 == nextFace) + return OWXFaceLayer(0,true); + // if the next face layer has either no smooth edge or + // no smooth edge of same nature, no next face + if(!nextFace->hasSmoothEdges()) + return OWXFaceLayer(0,true); + vector<WXFaceLayer*> sameNatureLayers; + nextFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers); + if((sameNatureLayers.empty()) || (sameNatureLayers.size() != 1)) // don't know how to deal with several edges of same nature on a single face + return OWXFaceLayer(0,true); + else{ + WXFaceLayer * winner = sameNatureLayers[0]; + if(woeend == winner->getSmoothEdge()->woea()->twin()) + return OWXFaceLayer(winner,true); + else + return OWXFaceLayer(winner,false); + } + } + return OWXFaceLayer(0,true); +} + +OWXFaceLayer ViewEdgeXBuilder::FindPreviousFaceLayer(const OWXFaceLayer& iFaceLayer) { + WXFace *previousFace = 0; + WOEdge * woebegin; + real tend; + if(iFaceLayer.order){ + woebegin = iFaceLayer.fl->getSmoothEdge()->woea(); + tend = iFaceLayer.fl->getSmoothEdge()->ta(); + }else{ + woebegin = iFaceLayer.fl->getSmoothEdge()->woeb(); + tend = iFaceLayer.fl->getSmoothEdge()->tb(); + } + + // special case of EDGE_VERTEX config: + if((tend == 0.0) || (tend == 1.0)){ + WVertex *previousVertex; + if(tend == 0.0) + previousVertex = woebegin->GetaVertex(); + else + previousVertex = woebegin->GetbVertex(); + if(previousVertex->isBoundary()) // if it's a non-manifold vertex -> ignore + return OWXFaceLayer(0,true); + bool found = false; + WVertex::face_iterator f=previousVertex->faces_begin(); + WVertex::face_iterator fend=previousVertex->faces_end(); + while((!found) && (f!=fend)){ + previousFace = dynamic_cast<WXFace*>(*f); + if((0 != previousFace) && (previousFace!=iFaceLayer.fl->getFace())){ + vector<WXFaceLayer*> sameNatureLayers; + previousFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers); + if(sameNatureLayers.size() == 1) {// don't know + // maybe should test whether this face has + // also a vertex_edge configuration + WXFaceLayer * winner = sameNatureLayers[0]; + if(woebegin == winner->getSmoothEdge()->woeb()->twin()) + return OWXFaceLayer(winner,true); + else + return OWXFaceLayer(winner,false); + } + } + ++f; + } + }else{ + previousFace = dynamic_cast<WXFace*>(iFaceLayer.fl->getFace()->GetBordingFace(woebegin)); + if(0 == previousFace) + return OWXFaceLayer(0,true); + + // if the next face layer has either no smooth edge or + // no smooth edge of same nature, no next face + if(!previousFace->hasSmoothEdges()) + return OWXFaceLayer(0,true); + vector<WXFaceLayer*> sameNatureLayers; + previousFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers); + if((sameNatureLayers.empty()) || (sameNatureLayers.size() != 1)) // don't know how to deal with several edges of same nature on a single face + return OWXFaceLayer(0,true); + else{ + WXFaceLayer * winner = sameNatureLayers[0]; + if(woebegin == winner->getSmoothEdge()->woeb()->twin()) + return OWXFaceLayer(winner,true); + else + return OWXFaceLayer(winner,false); + } + } + return OWXFaceLayer(0,true); +} + +FEdge * ViewEdgeXBuilder::BuildSmoothFEdge(FEdge *feprevious, const OWXFaceLayer& ifl){ + SVertex *va, *vb; + FEdgeSmooth *fe; + // retrieve exact silhouette data + WXSmoothEdge *se = ifl.fl->getSmoothEdge(); + + Vec3r normal; + // Make the 2 Svertices + if(feprevious == 0){ // that means that we don't have any vertex already built for that face + real ta = se->ta(); + Vec3r A1(se->woea()->GetaVertex()->GetVertex()); + Vec3r A2(se->woea()->GetbVertex()->GetVertex()); + Vec3r A(A1+ta*(A2-A1)); + + va = MakeSVertex(A); + // Set normal: + Vec3r NA1(ifl.fl->getFace()->GetVertexNormal(se->woea()->GetaVertex())); + Vec3r NA2(ifl.fl->getFace()->GetVertexNormal(se->woea()->GetbVertex())); + Vec3r na((1 - ta) * NA1 + ta * NA2); + na.normalize(); + va->AddNormal(na); + normal = na; + + // Set CurvatureInfo + CurvatureInfo* curvature_info_a = new CurvatureInfo(*(dynamic_cast<WXVertex*>(se->woea()->GetaVertex())->curvatures()), + *(dynamic_cast<WXVertex*>(se->woea()->GetbVertex())->curvatures()), + ta); + va->setCurvatureInfo(curvature_info_a); + } + else + va = feprevious->vertexB(); + + real tb = se->tb(); + Vec3r B1(se->woeb()->GetaVertex()->GetVertex()); + Vec3r B2(se->woeb()->GetbVertex()->GetVertex()); + Vec3r B(B1+tb*(B2-B1)); + + vb = MakeSVertex(B); + // Set normal: + Vec3r NB1(ifl.fl->getFace()->GetVertexNormal(se->woeb()->GetaVertex())); + Vec3r NB2(ifl.fl->getFace()->GetVertexNormal(se->woeb()->GetbVertex())); + Vec3r nb((1 - tb) * NB1 + tb * NB2); + nb.normalize(); + normal += nb; + vb->AddNormal(nb); + + // Set CurvatureInfo + CurvatureInfo* curvature_info_b = new CurvatureInfo(*(dynamic_cast<WXVertex*>(se->woeb()->GetaVertex())->curvatures()), + *(dynamic_cast<WXVertex*>(se->woeb()->GetbVertex())->curvatures()), + tb); + vb->setCurvatureInfo(curvature_info_b); + + // if the order is false we must swap va and vb + if(!ifl.order){ + SVertex *tmp = va; + va = vb; + vb = tmp; + } + + // Creates the corresponding feature edge + fe = new FEdgeSmooth(va, vb); + fe->setNature(ifl.fl->nature()); + fe->setId(_currentFId); + fe->setFrsMaterialIndex(ifl.fl->getFace()->frs_materialIndex()); + fe->setFace(ifl.fl->getFace()); + fe->setNormal(normal); + fe->setPreviousEdge(feprevious); + if(feprevious) + feprevious->setNextEdge(fe); + _pCurrentSShape->AddEdge(fe); + va->AddFEdge(fe); + vb->AddFEdge(fe); + + ++_currentFId; + ifl.fl->userdata = fe; + return fe; +} + +bool ViewEdgeXBuilder::stopSmoothViewEdge(WXFaceLayer *iFaceLayer){ + if(0 == iFaceLayer) + return true; + if(iFaceLayer->userdata == 0) + return false; + return true; +} + +OWXEdge ViewEdgeXBuilder::FindNextWEdge(const OWXEdge& iEdge){ + if(Nature::NO_FEATURE == iEdge.e->nature()) + return OWXEdge(0, true); + + WVertex *v; + if(true == iEdge.order) + v = iEdge.e->GetbVertex(); + else + v = iEdge.e->GetaVertex(); + + if(((WXVertex*)v)->isFeature()) + return 0; + + + vector<WEdge*>& vEdges = (v)->GetEdges(); + for(vector<WEdge*>::iterator ve=vEdges.begin(),veend=vEdges.end(); + ve!=veend; + ve++){ + WXEdge *wxe = dynamic_cast<WXEdge*>(*ve); + if(wxe == iEdge.e) + continue; // same edge as the one processed + + if(wxe->nature() != iEdge.e->nature()) + continue; + + if(wxe->GetaVertex() == v){ + // That means that the face necesarily lies on the edge left. + // So the vertex order is OK. + return OWXEdge(wxe, true); + }else{ + // That means that the face necesarily lies on the edge left. + // So the vertex order is OK. + return OWXEdge(wxe, false); + } + } + // we did not find: + return OWXEdge(0, true); +} + +OWXEdge ViewEdgeXBuilder::FindPreviousWEdge(const OWXEdge& iEdge){ + if(Nature::NO_FEATURE == iEdge.e->nature()) + return OWXEdge(0, true); + + WVertex *v; + if(true == iEdge.order) + v = iEdge.e->GetaVertex(); + else + v = iEdge.e->GetbVertex(); + + if(((WXVertex*)v)->isFeature()) + return 0; + + + vector<WEdge*>& vEdges = (v)->GetEdges(); + for(vector<WEdge*>::iterator ve=vEdges.begin(),veend=vEdges.end(); + ve!=veend; + ve++){ + WXEdge *wxe = dynamic_cast<WXEdge*>(*ve); + if(wxe == iEdge.e) + continue; // same edge as the one processed + + if(wxe->nature() != iEdge.e->nature()) + continue; + + if(wxe->GetbVertex() == v){ + return OWXEdge(wxe, true); + }else{ + return OWXEdge(wxe, false); + } + } + // we did not find: + return OWXEdge(0, true); +} + +FEdge * ViewEdgeXBuilder::BuildSharpFEdge(FEdge *feprevious, const OWXEdge& iwe){ + SVertex *va, *vb; + FEdgeSharp *fe; + WXVertex *wxVA, *wxVB; + if(iwe.order){ + wxVA = (WXVertex*)iwe.e->GetaVertex(); + wxVB = (WXVertex*)iwe.e->GetbVertex(); + }else{ + wxVA = (WXVertex*)iwe.e->GetbVertex(); + wxVB = (WXVertex*)iwe.e->GetaVertex(); + } + // Make the 2 SVertex + va = MakeSVertex(wxVA->GetVertex()); + vb = MakeSVertex(wxVB->GetVertex()); + + // get the faces normals and the material indices + Vec3r normalA, normalB; + unsigned matA(0), matB(0); + if(iwe.order){ + normalB = (iwe.e->GetbFace()->GetNormal()); + matB = (iwe.e->GetbFace()->frs_materialIndex()); + if(!(iwe.e->nature() & Nature::BORDER)) { + normalA = (iwe.e->GetaFace()->GetNormal()); + matA = (iwe.e->GetaFace()->frs_materialIndex()); + } + }else{ + normalA = (iwe.e->GetbFace()->GetNormal()); + matA = (iwe.e->GetbFace()->frs_materialIndex()); + if(!(iwe.e->nature() & Nature::BORDER)) { + normalB = (iwe.e->GetaFace()->GetNormal()); + matB = (iwe.e->GetaFace()->frs_materialIndex()); + } + } + // Creates the corresponding feature edge + // Creates the corresponding feature edge + fe = new FEdgeSharp(va, vb); + fe->setNature(iwe.e->nature()); + fe->setId(_currentFId); + fe->setaFrsMaterialIndex(matA); + fe->setbFrsMaterialIndex(matB); + fe->setNormalA(normalA); + fe->setNormalB(normalB); + fe->setPreviousEdge(feprevious); + if(feprevious) + feprevious->setNextEdge(fe); + _pCurrentSShape->AddEdge(fe); + va->AddFEdge(fe); + vb->AddFEdge(fe); + //Add normals: + va->AddNormal(normalA); + va->AddNormal(normalB); + vb->AddNormal(normalA); + vb->AddNormal(normalB); + + ++_currentFId; + iwe.e->userdata = fe; + return fe; +} + +bool ViewEdgeXBuilder::stopSharpViewEdge(WXEdge *iEdge){ + if(0 == iEdge) + return true; + if(iEdge->userdata == 0) + return false; + return true; +} + +SVertex * ViewEdgeXBuilder::MakeSVertex(Vec3r& iPoint){ + SVertex *va; + // Check whether the vertices are already in the table: + // fisrt vertex + // ------------- + SVertexMap::const_iterator found = _SVertexMap.find(iPoint); + if (found != _SVertexMap.end()) { + va = (*found).second; + }else{ + va = new SVertex(iPoint, _currentSVertexId); + SilhouetteGeomEngine::ProjectSilhouette(va); + ++_currentSVertexId; + // Add the svertex to the SShape svertex list: + _pCurrentSShape->AddNewVertex(va); + // Add the svertex in the table using its id: + _SVertexMap[iPoint] = va; + } + return va; +} + +ViewVertex * ViewEdgeXBuilder::MakeViewVertex(SVertex *iSVertex){ + ViewVertex *vva = iSVertex->viewvertex(); + if(vva != 0) + return vva; + vva = new NonTVertex(iSVertex); + // Add the view vertex to the ViewShape svertex list: + _pCurrentVShape->AddVertex(vva); + return vva; +} + diff --git a/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.h b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.h new file mode 100755 index 00000000000..28a5d7d9dd4 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewEdgeXBuilder.h @@ -0,0 +1,215 @@ +// +// Filename : ViewEdgeXBuilder.h +// Author(s) : Stephane Grabli +// Purpose : Class to build view edges and the underlying chains +// of feature edges... +// Date of creation : 27/10/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VIEWEDGEXBUILDER_H +# define VIEWEDGEXBUILDER_H + +# include <map> +# include <utility> +# include <vector> + +// soc +// # if defined(__GNUC__) && (__GNUC__ >= 3) +// //hash_map is not part of the C++ standard anymore; hash_map.h has been kept though for backward compatibility +// # include <hash_map.h> +// # else +// # include <hash_map> +// # endif + +# include "../system/FreestyleConfig.h" +# include "../geometry/Geom.h" +# include "Interface1D.h" + +using namespace Geometry; +using namespace std; + +class SVertex; +/*! Defines a hash table used for searching the SVertex */ +struct SVertexHasher { +#define _MUL 950706376UL +#define _MOD 2147483647UL + inline size_t operator() (const Vec3r& p) const { + size_t res = ((unsigned long) (p[0] * _MUL)) % _MOD; + res = ((res + (unsigned long) (p[1]) * _MUL)) % _MOD; + return ((res +(unsigned long) (p[2]) * _MUL)) % _MOD; + } +}; + +// Key_compare predicate for hash_map. In particular, return false if equal. +struct epsilonEquals{ + bool operator()(const Vec3r& v1, const Vec3r& v2) const{ + real norm = (v1-v2).norm(); + return (norm<1e-06); + } +}; + + +// typedef hash_map<Vec3r, SVertex*, SVertexHasher, epsilonEquals> SVertexMap; +typedef map<Vec3r , SVertex*> SVertexMap; + +class WXFaceLayer; +/*! class to describe an oriented smooth edge */ +class OWXFaceLayer{ +public: + WXFaceLayer * fl; + bool order; + + OWXFaceLayer() {fl=0;order=true;} + OWXFaceLayer(WXFaceLayer *ifl, bool iOrder=true){fl = ifl;order=iOrder;} + OWXFaceLayer& operator=(const OWXFaceLayer& iBrother){ + fl = iBrother.fl; + order = iBrother.order; + return *this; + } + bool operator==(const OWXFaceLayer& b){ + return ((fl == b.fl) && (order == b.order)); + } + bool operator!=(const OWXFaceLayer& b){ + return !(*this==b); + } +}; + +class WXEdge; +/*! class to describe an oriented sharp edge */ +class OWXEdge{ +public: + WXEdge * e; + bool order; + + OWXEdge() {e=0;order=true;} + OWXEdge(WXEdge *ie, bool iOrder=true){e = ie;order=iOrder;} + OWXEdge& operator=(const OWXEdge& iBrother){ + e = iBrother.e; + order = iBrother.order; + return *this; + } + bool operator==(const OWXEdge& b){ + return ((e == b.e) && (order == b.order)); + } + bool operator!=(const OWXEdge& b){ + return !(*this==b); + } +}; + +class WOEdge; +class WXEdge; +class WXShape; +class SVertex; +class FEdge; +class ViewVertex; +class ViewEdge; +class ViewShape; +class LIB_VIEW_MAP_EXPORT ViewEdgeXBuilder +{ +protected: + int _currentViewId; // Id for view edges + int _currentFId; // Id for FEdges + int _currentSVertexId; // Id for SVertex +public: + + inline ViewEdgeXBuilder() + {_currentViewId = 1;_currentFId=0;_currentSVertexId=0;} + virtual ~ViewEdgeXBuilder(){} + + /*! Builds a view shape from a WXShape in which the feature edges + * are flagged + * Builds chains of feature edges (so ViewEdges) from a WXShape + * iWShape + * The Winged Edge structure in which all silhouette edges + * and vertices are flagged. + * oViewShape + * The Silhouette Shape in which the chains must be added. + * ioVEdges + * The list of new ViewEdges. + * ioVVertices + * THe new ViewVertices + * ioFEdges + * A list in which all new FEdges are added + * ioSVertices + * A list of SVertex where all created SVertex are added. + */ + virtual void BuildViewEdges(WXShape *iWShape, ViewShape *oVShape, + std::vector<ViewEdge*>& ioVEdges, + std::vector<ViewVertex*>& ioVVertices, + std::vector<FEdge*>& ioFEdges, + std::vector<SVertex*>& ioSVertices) ; + + /*! Builds a smooth view edge, starting the face iFace.*/ + ViewEdge * BuildSmoothViewEdge(const OWXFaceLayer& iFaceLayer); + + /*! Makes a sharp viewedge + */ + ViewEdge * BuildSharpViewEdge(const OWXEdge& iWEdge) ; + + +public: + /*! accessors */ + inline int currentViewId() const { return _currentViewId; } + inline int currentFId() const { return _currentFId; } + inline int currentSVertexId() const { return _currentSVertexId; } + /*! modifiers */ + inline void setCurrentViewId(int id) { _currentViewId = id; } + inline void setCurrentFId(int id) { _currentFId = id; } + inline void setCurrentSVertexId(int id) { _currentSVertexId = id; } + +protected: + /*! Init the view edges building */ + virtual void Init(ViewShape *oVShape) ; + + // SMOOTH // + /*! checks whether a face has already been processed or not */ + bool stopSmoothViewEdge(WXFaceLayer *iFaceLayer); + OWXFaceLayer FindNextFaceLayer(const OWXFaceLayer& iFaceLayer); + OWXFaceLayer FindPreviousFaceLayer(const OWXFaceLayer& iFaceLayer); + FEdge * BuildSmoothFEdge(FEdge *feprevious, const OWXFaceLayer& ifl); + + // SHARP // + /*! checks whether a WEdge has already been processed or not */ + bool stopSharpViewEdge(WXEdge *iFace); + OWXEdge FindNextWEdge(const OWXEdge& iEdge); + OWXEdge FindPreviousWEdge(const OWXEdge& iEdge); + FEdge * BuildSharpFEdge(FEdge *feprevious, const OWXEdge& iwe); + + // GENERAL // + /*! Instanciate a SVertex if it hasn't been already created */ + SVertex * MakeSVertex(Vec3r& iPoint); + /*! instanciate a ViewVertex from a SVertex, if it doesn't exist yet */ + ViewVertex * MakeViewVertex(SVertex *iSVertex); + + //oldtmp values + // IdHashTable _hashtable; + // VVIdHashTable _multivertexHashTable; + SVertexMap _SVertexMap; + SShape *_pCurrentSShape; + ViewShape * _pCurrentVShape; +}; + +#endif + diff --git a/source/blender/freestyle/intern/view_map/ViewMap.cpp b/source/blender/freestyle/intern/view_map/ViewMap.cpp new file mode 100755 index 00000000000..87624669204 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMap.cpp @@ -0,0 +1,703 @@ + +// +// 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 "ViewMap.h" +#include "../geometry/GeomUtils.h" +#include <float.h> +#include "ViewMapIterators.h" +#include "ViewMapAdvancedIterators.h" + + /**********************************/ + /* */ + /* */ + /* ViewMap */ + /* */ + /* */ + /**********************************/ + +ViewMap * ViewMap::_pInstance = 0; + +ViewMap::~ViewMap() +{ + // The view vertices must be deleted here as some of them + // are shared between two shapes: + for(vector<ViewVertex*>::iterator vv=_VVertices.begin(), vvend=_VVertices.end(); + vv!=vvend; + vv++) + { + delete (*vv); + } + _VVertices.clear(); + + for(vector<ViewShape*>::iterator vs=_VShapes.begin(),vsend=_VShapes.end(); + vs!=vsend; + vs++) + { + delete (*vs); + } + _VShapes.clear(); + + _FEdges.clear(); + _SVertices.clear(); + _VEdges.clear(); +} + +ViewShape * ViewMap::viewShape(unsigned id) +{ + int index = _shapeIdToIndex[id]; + return _VShapes[ index ]; +} +void ViewMap::AddViewShape(ViewShape *iVShape) { + _shapeIdToIndex[iVShape->getId().getFirst()] = _VShapes.size(); + _VShapes.push_back(iVShape); +} +const FEdge * ViewMap::getClosestFEdge(real x, real y) const +{ + // find the closest of this candidates: + real minDist = DBL_MAX; + FEdge * winner = 0; + for(fedges_container::const_iterator fe=_FEdges.begin(),feend=_FEdges.end(); + fe!=feend; + fe++) + { + Vec2d A((*fe)->vertexA()->point2D()[0], (*fe)->vertexA()->point2D()[1]); + Vec2d B((*fe)->vertexB()->point2D()[0], (*fe)->vertexB()->point2D()[1]); + real dist = GeomUtils::distPointSegment<Vec2r>(Vec2r(x,y),A, B); + if(dist < minDist) + { + minDist = dist; + winner = (*fe); + } + + } + if(winner==0) + return 0; + + return winner; +} + +const ViewEdge * ViewMap::getClosestViewEdge(real x, real y) const +{ + // find the closest of this candidates: + real minDist = DBL_MAX; + FEdge * winner = 0; + for(fedges_container::const_iterator fe=_FEdges.begin(),feend=_FEdges.end(); + fe!=feend; + fe++) + { + Vec2d A((*fe)->vertexA()->point2D()[0], (*fe)->vertexA()->point2D()[1]); + Vec2d B((*fe)->vertexB()->point2D()[0], (*fe)->vertexB()->point2D()[1]); + real dist = GeomUtils::distPointSegment<Vec2r>(Vec2r(x,y),A, B); + if(dist < minDist) + { + minDist = dist; + winner = (*fe); + } + + } + if(winner==0) + return 0; + + return winner->viewedge(); +} + + +TVertex* ViewMap::CreateTVertex(const Vec3r& iA3D, const Vec3r& iA2D, FEdge *iFEdgeA, + const Vec3r& iB3D, const Vec3r& iB2D, FEdge *iFEdgeB, + const Id& id) +{ + ViewShape *vshapeA = iFEdgeA->viewedge()->viewShape(); + SShape *shapeA = iFEdgeA->shape(); + ViewShape *vshapeB = iFEdgeB->viewedge()->viewShape(); + SShape *shapeB = iFEdgeB->shape(); + + SVertex * Ia = shapeA->CreateSVertex(iA3D, iA2D, iFEdgeA->vertexA()->getId()); + SVertex * Ib = shapeB->CreateSVertex(iB3D, iB2D, iFEdgeB->vertexA()->getId()); + + // depending on which of these 2 svertices is the nearest from the + // viewpoint, we're going to build the TVertex by giving them in + // an order or another (the first one must be the nearest) + real dista = Ia->point2D()[2]; + real distb = Ib->point2D()[2]; + + TVertex * tvertex; + if(dista < distb) + tvertex = new TVertex(Ia, Ib); + else + tvertex = new TVertex(Ib,Ia); + + tvertex->setId(id); + + // add these vertices to the view map + AddViewVertex(tvertex); + AddSVertex(Ia); + AddSVertex(Ib); + + // and this T Vertex to the view shapes: + vshapeA->AddVertex(tvertex); + vshapeB->AddVertex(tvertex); + + return tvertex; +} + +ViewVertex * ViewMap::InsertViewVertex(SVertex *iVertex, + vector<ViewEdge*>& newViewEdges){ + NonTVertex *vva = dynamic_cast<NonTVertex*>(iVertex->viewvertex()); + if(vva != 0) + return vva; + // beacuse it is not already a ViewVertex, this SVertex must have only + // 2 FEdges. The incoming one still belongs to ioEdge, the outgoing one + // now belongs to newVEdge + const vector<FEdge*>& fedges = iVertex->fedges(); + if(fedges.size()!=2){ + cerr << "ViewMap warning: Can't split the ViewEdge" << endl; + return 0; + } + FEdge * fend(0), * fbegin(0); + for(vector<FEdge*>::const_iterator fe=fedges.begin(), feend=fedges.end(); + fe!=feend; + ++fe){ + if((*fe)->vertexB() == iVertex){ + fend = (*fe); + } + if((*fe)->vertexA() == iVertex){ + fbegin = (*fe); + } + if((fbegin!=0) && (fend!=0)) + break; + } + ViewEdge *ioEdge = fbegin->viewedge(); + ViewShape * vshape = ioEdge->viewShape(); + vva = new NonTVertex(iVertex); + // if the ViewEdge is a closed loop, we don't create + // a new VEdge + if(ioEdge->A() == 0){ + // closed loop + ioEdge->setA(vva); + ioEdge->setB(vva); + // update sshape + vshape->sshape()->RemoveEdgeFromChain(ioEdge->fedgeA()); + vshape->sshape()->RemoveEdgeFromChain(ioEdge->fedgeB()); + + ioEdge->setFEdgeA(fbegin); + ioEdge->setFEdgeB(fend); + + // Update FEdges + fend->setNextEdge(0); + fbegin->setPreviousEdge(0); + + // update new View Vertex: + vva->AddOutgoingViewEdge(ioEdge); + vva->AddIncomingViewEdge(ioEdge); + + vshape->sshape()->AddChain(ioEdge->fedgeA()); + vshape->sshape()->AddChain(ioEdge->fedgeB()); + }else{ + // Create new ViewEdge + ViewEdge * newVEdge = new ViewEdge(vva, ioEdge->B(), fbegin, ioEdge->fedgeB(), vshape); + newVEdge->setId(Id(ioEdge->getId().getFirst(), ioEdge->getId().getSecond()+1)); + newVEdge->setNature(ioEdge->getNature()); + //newVEdge->UpdateFEdges(); // done in the ViewEdge constructor + // Update old ViewEdge + ioEdge->setB(vva); + ioEdge->setFEdgeB(fend); + + // Update FEdges + fend->setNextEdge(0); + fbegin->setPreviousEdge(0); + + // update new View Vertex: + vva->AddOutgoingViewEdge(newVEdge); + vva->AddIncomingViewEdge(ioEdge); + // update ViewShape + //vshape->AddEdge(newVEdge); + // update SShape + vshape->sshape()->AddChain(fbegin); + // update ViewMap + //_VEdges.push_back(newVEdge); + newViewEdges.push_back(newVEdge); + } + + // update ViewShape + vshape->AddVertex(vva); + + // update ViewMap + _VVertices.push_back(vva); + + return vva; +} + +//FEdge * ViewMap::Connect(FEdge *ioEdge, SVertex *ioVertex, vector<ViewEdge*>& oNewVEdges){ +// SShape * sshape = ioEdge->shape(); +// FEdge *newFEdge = sshape->SplitEdgeIn2(ioEdge, ioVertex); +// AddFEdge(newFEdge); +// InsertViewVertex(ioVertex, oNewVEdges); +// return newFEdge; +//} + + /**********************************/ + /* */ + /* */ + /* TVertex */ + /* */ + /* */ + /**********************************/ + +// is dve1 before dve2 ? (does it have a smaller angle ?) +bool ViewEdgeComp(ViewVertex::directedViewEdge& dve1, ViewVertex::directedViewEdge& dve2){ + FEdge *fe1; + if(dve1.second) + fe1 = dve1.first->fedgeB(); + else + fe1 = dve1.first->fedgeA(); + FEdge *fe2; + if(dve2.second) + fe2 = dve2.first->fedgeB(); + else + fe2 = dve2.first->fedgeA(); + + Vec3r V1 = fe1->orientation2d(); + Vec2r v1(V1.x(), V1.y());v1.normalize(); + Vec3r V2 = fe2->orientation2d(); + Vec2r v2(V2.x(), V2.y());v2.normalize(); + if(v1.y() > 0){ + if(v2.y() < 0) + return true; + else + return (v1.x() > v2.x()); + }else{ + if(v2.y() > 0) + return false; + else + return (v1.x() < v2.x()); + } + return false; +} +void TVertex::setFrontEdgeA(ViewEdge *iFrontEdgeA, bool incoming) { + if (!iFrontEdgeA) { + cerr << "Warning: null pointer passed as argument of TVertex::setFrontEdgeA()" << endl; + return; + } + _FrontEdgeA = directedViewEdge(iFrontEdgeA, incoming); + if(!_sortedEdges.empty()){ + edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end(); + while((dve!=dveend) && ViewEdgeComp(**dve, _FrontEdgeA)){ + ++dve; + } + _sortedEdges.insert( dve, &_FrontEdgeA); + } + else + _sortedEdges.push_back(&_FrontEdgeA); +} +void TVertex::setFrontEdgeB(ViewEdge *iFrontEdgeB, bool incoming) { + if (!iFrontEdgeB) { + cerr << "Warning: null pointer passed as argument of TVertex::setFrontEdgeB()" << endl; + return; + } + _FrontEdgeB = directedViewEdge(iFrontEdgeB, incoming); + if(!_sortedEdges.empty()){ + edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end(); + while((dve!=dveend) && ViewEdgeComp(**dve, _FrontEdgeB)){ + ++dve; + } + _sortedEdges.insert(dve, &_FrontEdgeB); + } + else + _sortedEdges.push_back(&_FrontEdgeB); +} +void TVertex::setBackEdgeA(ViewEdge *iBackEdgeA, bool incoming) { + if (!iBackEdgeA) { + cerr << "Warning: null pointer passed as argument of TVertex::setBackEdgeA()" << endl; + return; + } + _BackEdgeA = directedViewEdge(iBackEdgeA, incoming); + if(!_sortedEdges.empty()){ + edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end(); + while((dve!=dveend) && ViewEdgeComp(**dve, _BackEdgeA)){ + ++dve; + } + _sortedEdges.insert(dve, &_BackEdgeA); + } + else + _sortedEdges.push_back(&_BackEdgeA); +} +void TVertex::setBackEdgeB(ViewEdge *iBackEdgeB, bool incoming) { + if (!iBackEdgeB) { + cerr << "Warning: null pointer passed as argument of TVertex::setBackEdgeB()" << endl; + return; + } + _BackEdgeB = directedViewEdge(iBackEdgeB, incoming); + if(!_sortedEdges.empty()){ + edge_pointers_container::iterator dve = _sortedEdges.begin(), dveend = _sortedEdges.end(); + while((dve!=dveend) && ViewEdgeComp(**dve, _BackEdgeB)){ + ++dve; + } + _sortedEdges.insert(dve, &_BackEdgeB); + } + else + _sortedEdges.push_back(&_BackEdgeB); +} +void TVertex::Replace(ViewEdge *iOld, ViewEdge *iNew) +{ + // theoritically, we only replace edges for which this + // view vertex is the B vertex + if((iOld == _FrontEdgeA.first) && (_FrontEdgeA.first->B() == this)) + { + _FrontEdgeA.first = iNew; + return; + } + if((iOld == _FrontEdgeB.first) && (_FrontEdgeB.first->B() == this)) + { + _FrontEdgeB.first = iNew; + return; + } + if((iOld == _BackEdgeA.first) && (_BackEdgeA.first->B() == this)) + { + _BackEdgeA.first = iNew; + return; + } + if((iOld == _BackEdgeB.first) && (_BackEdgeB.first->B() == this)) + { + _BackEdgeB.first = iNew; + return; + } +} + +/*! iterators access */ +ViewVertex::edge_iterator TVertex::edges_begin() +{ + //return edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, _FrontEdgeA); + return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin()); +} +ViewVertex::const_edge_iterator TVertex::edges_begin() const +{ + //return const_edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, _FrontEdgeA); + return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin()); +} +ViewVertex::edge_iterator TVertex::edges_end() +{ + //return edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, directedViewEdge(0,true)); + return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.end()); +} +ViewVertex::const_edge_iterator TVertex::edges_end() const +{ + //return const_edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, directedViewEdge(0, true)); + return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.end()); +} +ViewVertex::edge_iterator TVertex::edges_iterator(ViewEdge *iEdge) +{ + for(edge_pointers_container::iterator it=_sortedEdges.begin(), itend=_sortedEdges.end(); + it!=itend; + it++) + { + if((*it)->first == iEdge) + return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), it); + } + return edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin()); + + // directedViewEdge dEdge; + // if(_FrontEdgeA.first == iEdge) + // dEdge = _FrontEdgeA; + // else if(_FrontEdgeB.first == iEdge) + // dEdge = _FrontEdgeB; + // else if(_BackEdgeA.first == iEdge) + // dEdge = _BackEdgeA; + // else if(_BackEdgeB.first == iEdge) + // dEdge = _BackEdgeB; + // return edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, dEdge); +} +ViewVertex::const_edge_iterator TVertex::edges_iterator(ViewEdge *iEdge) const +{ + for(edge_pointers_container::const_iterator it=_sortedEdges.begin(), itend=_sortedEdges.end(); + it!=itend; + it++) + { + if((*it)->first == iEdge) + return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), it); + } + return const_edge_iterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin()); + + // directedViewEdge dEdge; + // if(_FrontEdgeA.first == iEdge) + // dEdge = _FrontEdgeA; + // else if(_FrontEdgeB.first == iEdge) + // dEdge = _FrontEdgeB; + // else if(_BackEdgeA.first == iEdge) + // dEdge = _BackEdgeA; + // else if(_BackEdgeB.first == iEdge) + // dEdge = _BackEdgeB; + // return const_edge_iterator(_FrontEdgeA, _FrontEdgeB, _BackEdgeA, _BackEdgeB, dEdge); +} + +ViewVertexInternal::orientedViewEdgeIterator TVertex::edgesBegin() { + return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin()); +} +ViewVertexInternal::orientedViewEdgeIterator TVertex::edgesEnd() { + return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.end()); +} +ViewVertexInternal::orientedViewEdgeIterator TVertex::edgesIterator(ViewEdge *iEdge) { + for(edge_pointers_container::iterator it=_sortedEdges.begin(), itend=_sortedEdges.end(); + it!=itend; + it++) + { + if((*it)->first == iEdge) + return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), it); + } + return ViewVertexInternal::orientedViewEdgeIterator(_sortedEdges.begin(), _sortedEdges.end(), _sortedEdges.begin()); +} + /**********************************/ + /* */ + /* */ + /* NonTVertex */ + /* */ + /* */ + /**********************************/ + +void NonTVertex::AddOutgoingViewEdge(ViewEdge * iVEdge){ + // let's keep the viewedges ordered in CCW order + // in the 2D image plan + directedViewEdge idve(iVEdge, false); + if(!_ViewEdges.empty()){ + edges_container::iterator dve = _ViewEdges.begin(), dveend = _ViewEdges.end(); + while((dve!=dveend) && ViewEdgeComp(*dve, idve)){ + ++dve; + } + _ViewEdges.insert(dve, idve); + } + else + _ViewEdges.push_back(idve); +} + +void NonTVertex::AddIncomingViewEdge(ViewEdge * iVEdge){ + // let's keep the viewedges ordered in CCW order + // in the 2D image plan + directedViewEdge idve(iVEdge, true); + if(!_ViewEdges.empty()){ + edges_container::iterator dve = _ViewEdges.begin(), dveend = _ViewEdges.end(); + while((dve!=dveend) && ViewEdgeComp(*dve, idve)){ + ++dve; + } + _ViewEdges.insert(dve, idve); + } + else + _ViewEdges.push_back(idve); +} + +/*! iterators access */ +ViewVertex::edge_iterator NonTVertex::edges_begin() +{ + return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin()); +} +ViewVertex::const_edge_iterator NonTVertex::edges_begin() const +{ + return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin()); +} +ViewVertex::edge_iterator NonTVertex::edges_end() +{ + return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.end()); +} +ViewVertex::const_edge_iterator NonTVertex::edges_end() const +{ + return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.end()); +} +ViewVertex::edge_iterator NonTVertex::edges_iterator(ViewEdge *iEdge) +{ + for(edges_container::iterator it=_ViewEdges.begin(), itend=_ViewEdges.end(); + it!=itend; + it++) + { + if((it)->first == iEdge) + return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), it); + } + return edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin()); +} +ViewVertex::const_edge_iterator NonTVertex::edges_iterator(ViewEdge *iEdge) const +{ + for(edges_container::const_iterator it=_ViewEdges.begin(), itend=_ViewEdges.end(); + it!=itend; + it++) + { + if((it)->first == iEdge) + return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), it); + } + return const_edge_iterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin()); +} + +ViewVertexInternal::orientedViewEdgeIterator NonTVertex::edgesBegin() { + return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin()); +} +ViewVertexInternal::orientedViewEdgeIterator NonTVertex::edgesEnd() { + return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.end()); +} +ViewVertexInternal::orientedViewEdgeIterator NonTVertex::edgesIterator(ViewEdge *iEdge) { + for(edges_container::iterator it=_ViewEdges.begin(), itend=_ViewEdges.end(); + it!=itend; + it++) + { + if((it)->first == iEdge) + return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), it); + } + return ViewVertexInternal::orientedViewEdgeIterator(_ViewEdges.begin(), _ViewEdges.end(), _ViewEdges.begin()); +} + /**********************************/ + /* */ + /* */ + /* ViewEdge */ + /* */ + /* */ + /**********************************/ + +real ViewEdge::getLength2D() const +{ + float length = 0.f; + ViewEdge::const_fedge_iterator itlast = fedge_iterator_last(); + ViewEdge::const_fedge_iterator it = fedge_iterator_begin(), itend=fedge_iterator_end(); + Vec2r seg; + do{ + seg = Vec2r((*it)->orientation2d()[0], (*it)->orientation2d()[1]); + length += seg.norm(); + ++it; + }while((it!=itend) && (it!=itlast)); + return length; +} + + +//! view edge iterator +ViewEdge::edge_iterator ViewEdge::ViewEdge_iterator() {return edge_iterator(this);} +ViewEdge::const_edge_iterator ViewEdge::ViewEdge_iterator() const {return const_edge_iterator((ViewEdge*)this);} +//! feature edge iterator +ViewEdge::fedge_iterator ViewEdge::fedge_iterator_begin() {return fedge_iterator(this->_FEdgeA, this->_FEdgeB);} +ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_begin() const {return const_fedge_iterator(this->_FEdgeA, this->_FEdgeB);} +ViewEdge::fedge_iterator ViewEdge::fedge_iterator_last() {return fedge_iterator(this->_FEdgeB, this->_FEdgeB);} +ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_last() const {return const_fedge_iterator(this->_FEdgeB, this->_FEdgeB);} +ViewEdge::fedge_iterator ViewEdge::fedge_iterator_end() {return fedge_iterator(0, this->_FEdgeB);} +ViewEdge::const_fedge_iterator ViewEdge::fedge_iterator_end() const {return const_fedge_iterator(0, this->_FEdgeB);} +//! embedding vertex iterator +ViewEdge::const_vertex_iterator ViewEdge::vertices_begin() const {return const_vertex_iterator(this->_FEdgeA->vertexA(), 0, _FEdgeA);} +ViewEdge::vertex_iterator ViewEdge::vertices_begin() {return vertex_iterator(this->_FEdgeA->vertexA(), 0, _FEdgeA);} +ViewEdge::const_vertex_iterator ViewEdge::vertices_last() const {return const_vertex_iterator(this->_FEdgeB->vertexB(), _FEdgeB, 0);} +ViewEdge::vertex_iterator ViewEdge::vertices_last() {return vertex_iterator(this->_FEdgeB->vertexB(), _FEdgeB, 0);} +ViewEdge::const_vertex_iterator ViewEdge::vertices_end() const {return const_vertex_iterator(0, _FEdgeB, 0);} +ViewEdge::vertex_iterator ViewEdge::vertices_end() {return vertex_iterator(0, _FEdgeB, 0);} + + +Interface0DIterator ViewEdge::verticesBegin() { + Interface0DIterator ret(new ViewEdgeInternal::SVertexIterator(this->_FEdgeA->vertexA(), this->_FEdgeA->vertexA(), 0, _FEdgeA, 0.f)); + return ret; +} + +Interface0DIterator ViewEdge::verticesEnd() { + Interface0DIterator ret(new ViewEdgeInternal::SVertexIterator(0, this->_FEdgeA->vertexA(), _FEdgeB, 0, getLength2D())); + return ret; +} + +Interface0DIterator ViewEdge::pointsBegin(float t) { + return verticesBegin(); +} + +Interface0DIterator ViewEdge::pointsEnd(float t) { + return verticesEnd(); +} + + + + /**********************************/ + /* */ + /* */ + /* ViewShape */ + /* */ + /* */ + /**********************************/ + + +ViewShape::~ViewShape() +{ + _Vertices.clear(); + + if(!(_Edges.empty())) + { + for(vector<ViewEdge*>::iterator e=_Edges.begin(), eend=_Edges.end(); + e!=eend; + e++) + { + delete (*e); + } + _Edges.clear(); + } + + if(0 != _SShape) + { + delete _SShape; + _SShape = 0; + } +} + +void ViewShape::RemoveEdge(ViewEdge * iViewEdge) +{ + FEdge * fedge = iViewEdge->fedgeA(); + for(vector<ViewEdge*>::iterator ve=_Edges.begin(),veend=_Edges.end(); + ve!=veend; + ve++) + { + if(iViewEdge == (*ve)) + { + _Edges.erase(ve); + _SShape->RemoveEdge(fedge); + break; + } + } +} + +void ViewShape::RemoveVertex(ViewVertex * iViewVertex) +{ + for(vector<ViewVertex*>::iterator vv=_Vertices.begin(), vvend=_Vertices.end(); + vv!=vvend; + vv++) + { + if(iViewVertex == (*vv)) + { + _Vertices.erase(vv); + break; + } + } +} + + /**********************************/ + /* */ + /* */ + /* ViewEdge */ + /* */ + /* */ + /**********************************/ + + +void ViewEdge::UpdateFEdges() +{ + FEdge *currentEdge = _FEdgeA; + do + { + currentEdge->setViewEdge(this); + currentEdge = currentEdge->nextEdge(); + }while((currentEdge != NULL) && (currentEdge!= _FEdgeB)); + // last one + _FEdgeB->setViewEdge(this); + +} diff --git a/source/blender/freestyle/intern/view_map/ViewMap.h b/source/blender/freestyle/intern/view_map/ViewMap.h new file mode 100755 index 00000000000..5a9d8f3b57b --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMap.h @@ -0,0 +1,1492 @@ +// +// Filename : ViewMap.h +// Author(s) : Stephane Grabli +// Purpose : Classes to define a View Map (ViewVertex, ViewEdge, etc.) +// Date of creation : 03/09/2002 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VIEWMAP_H +# define VIEWMAP_H + +# include "Interface0D.h" +# include "Interface1D.h" +# include "Silhouette.h" // defines the embedding +# include "../system/BaseIterator.h" +# include "../system/FreestyleConfig.h" +# include "../geometry/GeomUtils.h" +# include <map> + + /**********************************/ + /* */ + /* */ + /* ViewMap */ + /* */ + /* */ + /**********************************/ + + +/* Density + Mean area depth value + distance to a point + */ + +class ViewVertex; +class ViewEdge; +class ViewShape; +class TVertex; + +/*! Class defining the ViewMap.*/ +class LIB_VIEW_MAP_EXPORT ViewMap +{ +public: + + typedef vector<ViewEdge*> viewedges_container; + typedef vector<ViewVertex*> viewvertices_container; + typedef vector<ViewShape*> viewshapes_container; + typedef vector<SVertex*> svertices_container; + typedef vector<FEdge*> fedges_container; + typedef map<int,int> id_to_index_map; + +private: + + static ViewMap *_pInstance; + viewshapes_container _VShapes; // view shapes + viewedges_container _VEdges; // view edges + viewvertices_container _VVertices; // view vertices + fedges_container _FEdges; // feature edges (embedded edges) + svertices_container _SVertices; // embedded vertices + BBox<Vec3r> _scene3DBBox; + id_to_index_map _shapeIdToIndex; // Mapping between the WShape or VShape id to the VShape index in the + // _VShapes vector. Used in the method viewShape(int id) to access a shape from its id. + +public: + + /*! A field that can be used by the user to store any data. + * This field must be reseted afterwards using ResetUserData(). + */ + void* userdata; + + /*! Default constructor. */ + ViewMap() { + _pInstance = this; + userdata = 0; + } + /*! Destructor. */ + virtual ~ViewMap(); + + /*! Gets the viewedge the nearest to the + * 2D position specified as argument + */ + const ViewEdge * getClosestViewEdge(real x, real y) const ; + + /*! Gets the Fedge the nearest to the + * 2D position specified as argument + */ + const FEdge * getClosestFEdge(real x, real y) const ; + + /* accessors */ + /*! The ViewMap is a singleton class. This static method + * returns the instance of the ViewMap. + */ + static inline ViewMap * getInstance() {return _pInstance;} + /* Returns the list of ViewShapes of the scene. */ + inline viewshapes_container& ViewShapes() {return _VShapes;} + /* Returns the list of ViewEdges of the scene. */ + inline viewedges_container& ViewEdges() {return _VEdges;} + /* Returns the list of ViewVertices of the scene. */ + inline viewvertices_container& ViewVertices() {return _VVertices;} + /* Returns the list of FEdges of the scene. */ + inline fedges_container& FEdges() {return _FEdges;} + /* Returns the list of SVertices of the scene. */ + inline svertices_container& SVertices() {return _SVertices;} + /* Returns an iterator pointing onto the first ViewEdge of the list. */ + inline viewedges_container::iterator viewedges_begin() {return _VEdges.begin();} + inline viewedges_container::iterator viewedges_end() {return _VEdges.end();} + inline int viewedges_size() {return _VEdges.size();} + ViewShape * viewShape(unsigned index); + id_to_index_map& shapeIdToIndexMap() {return _shapeIdToIndex;} + + /*! Returns the scene 3D bounding box. */ + inline BBox<Vec3r> getScene3dBBox() const {return _scene3DBBox;} + + /* modifiers */ + void AddViewShape(ViewShape *iVShape); + inline void AddViewEdge(ViewEdge *iVEdge) {_VEdges.push_back(iVEdge);} + inline void AddViewVertex(ViewVertex *iVVertex) {_VVertices.push_back(iVVertex);} + inline void AddFEdge(FEdge *iFEdge) {_FEdges.push_back(iFEdge);} + inline void AddSVertex(SVertex *iSVertex) {_SVertices.push_back(iSVertex);} + /*! Sets the scene 3D bounding box. */ + inline void setScene3dBBox(const BBox<Vec3r>& bbox) {_scene3DBBox=bbox;} + + /* Creates a T vertex in the view map. + * A T vertex is the intersection between 2 + * FEdges (before these ones are splitted). + * The TVertex is a 2D intersection but it + * corresponds to a 3D point on each of the 2 FEdges. + * iA3D + * The 3D coordinates of the point corresponding + * to the intersection on the first edge. + * iA2D + * The x,y,z 2D coordinates of the projection + * of iA3D + * iFEdgeA + * The first FEdge + * iB3D + * The 3D coordinates of the point corresponding + * to the intersection on the second edge. + * iB2D + * The x,y,z 2D coordinates of the projection + * of iB3D + * iFEdgeB + * The second FEdge + * id + * The id that must be given to that TVertex + */ + TVertex* CreateTVertex(const Vec3r& iA3D, const Vec3r& iA2D, FEdge *iFEdgeA, + const Vec3r& iB3D, const Vec3r& iB2D, FEdge *iFEdgeB, + const Id& id); + + /* Updates the structures to take into account the fact + * that a SVertex must now be considered as a ViewVertex + * iVertex + * The SVertex on top of which the ViewVertex is built (it is necessarily + * a NonTVertex because it is a SVertex) + * newViewEdges + * The new ViewEdges that must be add to the ViewMap + */ + ViewVertex * InsertViewVertex(SVertex *iVertex, vector<ViewEdge*>& newViewEdges); + + /* connects a FEdge to the graph trough a SVertex */ + //FEdge * Connect(FEdge *ioEdge, SVertex *ioVertex); +}; + + /**********************************/ + /* */ + /* */ + /* ViewVertex */ + /* */ + /* */ + /**********************************/ + +class ViewEdge; +class SShape; + +namespace ViewVertexInternal { + class edge_const_traits; + class edge_nonconst_traits; + template<class Traits> class edge_iterator_base ; + class orientedViewEdgeIterator; +} // end of namespace ViewEdgeInternal +/*! Class to define a view vertex + * A view vertex is a feature vertex corresponding + * to a point of the image graph, where the characteristics of an + * edge might change (nature, visibility, ...). + * A ViewVertex can be of two kinds: a TVertex when + * it corresponds to the intersection between two + * ViewEdges or a NonTVertex when it corresponds to a + * vertex of the initial input mesh (it is the case + * for vertices such as corners for example). + * Thus, this class can be specialized into two classes, + * the TVertex class and the NonTVertex class. + */ +class LIB_VIEW_MAP_EXPORT ViewVertex : public Interface0D +{ +public: // Implementation of Interface0D + + /*! Returns the string "ViewVertex" .*/ + virtual string getExactTypeName() const { + return "ViewVertex"; + } + +public: + friend class ViewShape; + typedef pair<ViewEdge*, bool> directedViewEdge; // if bool = true, the ViewEdge is incoming + + typedef vector<directedViewEdge> edges_container; + + typedef ViewVertexInternal::edge_iterator_base<ViewVertexInternal::edge_nonconst_traits> edge_iterator; + typedef ViewVertexInternal::edge_iterator_base<ViewVertexInternal::edge_const_traits> const_edge_iterator; + +private: + + Nature::VertexNature _Nature; + +public: + /*! A field that can be used by the user to store any data. + * This field must be reseted afterwards using ResetUserData(). + */ + void * userdata; + /*! Default constructor.*/ + inline ViewVertex() {userdata = 0;_Nature = Nature::VIEW_VERTEX; } + inline ViewVertex(Nature::VertexNature nature) { + userdata = 0; + _Nature = Nature::VIEW_VERTEX | nature; + } + +protected: + /*! Copy constructor. */ + inline ViewVertex(ViewVertex& iBrother) + { + _Nature = iBrother._Nature; + iBrother.userdata = this; + userdata = 0; + } + /*! Cloning method. */ + virtual ViewVertex * duplicate() = 0; + +public: + /*! Destructor. */ + virtual ~ViewVertex() {} + + /* accessors */ + /*! Returns the nature of the vertex .*/ + virtual Nature::VertexNature getNature() const { + return _Nature; + } + + /* modifiers */ + /*! Sets the nature of the vertex. */ + inline void setNature(Nature::VertexNature iNature) {_Nature = iNature;} + + /* Replaces old edge by new edge */ + virtual void Replace(ViewEdge *, ViewEdge *) {} + +public: + + /* iterators access */ + // allows iteration on the edges that comes from/goes to + // this vertex in CCW order (order defined in 2D in the image plan) + virtual edge_iterator edges_begin() = 0; + virtual const_edge_iterator edges_begin() const = 0; + virtual edge_iterator edges_end() = 0; + virtual const_edge_iterator edges_end() const = 0; + virtual edge_iterator edges_iterator(ViewEdge *iEdge) = 0; + virtual const_edge_iterator edges_iterator(ViewEdge *iEdge) const = 0; + + + // Iterator access + /*! Returns an iterator over the ViewEdges that goes to or comes from + * this ViewVertex pointing to the first ViewEdge of the list. + * The orientedViewEdgeIterator allows to iterate in CCW order over these ViewEdges + * and to get the orientation for each ViewEdge (incoming/outgoing). + */ + virtual ViewVertexInternal::orientedViewEdgeIterator edgesBegin() = 0; + + /*! Returns an orientedViewEdgeIterator over the ViewEdges around this ViewVertex, + * pointing after the last ViewEdge. + */ + virtual ViewVertexInternal::orientedViewEdgeIterator edgesEnd() = 0; + + /*! Returns an orientedViewEdgeIterator pointing to the ViewEdge + * given as argument. + */ + virtual ViewVertexInternal::orientedViewEdgeIterator edgesIterator(ViewEdge *iEdge) = 0; + +}; + + /**********************************/ + /* */ + /* */ + /* TVertex */ + /* */ + /* */ + /**********************************/ + +/*! class to define a T vertex, i.e. an intersection between + * two edges. + * It points towards 2 SVertex and 4 View edges. + * Among these ViewEdges, 2 are front and 2 are back. + * Basically the front edge hides part of the back edge. + * So, among the back edges, 1 is of invisibility n + * and the other of visibility n+1 + */ +class LIB_VIEW_MAP_EXPORT TVertex : public ViewVertex +{ +public: + typedef vector<directedViewEdge*> edge_pointers_container; +public: // Implementation of Interface0D + + /*! Returns the string "TVertex" .*/ + virtual string getExactTypeName() const { + return "TVertex"; + } + + // Data access methods + /* Returns the 3D x coordinate of the vertex . + * Ambiguous in this case. + */ + virtual real getX() const { + cerr << "Warning: getX() undefined for this point" << endl; + return _FrontSVertex->point3D().x(); + } + + virtual real getY() const { + cerr << "Warning: getX() undefined for this point" << endl; + return _FrontSVertex->point3D().y(); + } + + virtual real getZ() const { + cerr << "Warning: getX() undefined for this point" << endl; + return _FrontSVertex->point3D().z(); + } + + /*! Returns the 3D point. */ + virtual Vec3f getPoint3D() const { + cerr << "Warning: getPoint3D() undefined for this point" << endl; + return _FrontSVertex->getPoint3D(); + } + + /*! Returns the projected 3D x coordinate of the vertex .*/ + virtual real getProjectedX() const { + return _FrontSVertex->point2D().x(); + } + + /*! Returns the projected 3D y coordinate of the vertex .*/ + virtual real getProjectedY() const { + return _FrontSVertex->point2D().y(); + } + + virtual real getProjectedZ() const { + return _FrontSVertex->point2D().z(); + } + + /*! Returns the 2D point. */ + virtual Vec2f getPoint2D() const { + return _FrontSVertex->getPoint2D(); + } + + /*! Returns the Id of the TVertex .*/ + virtual Id getId() const { + return _Id; + } + + /*! Cast the Interface0D in SVertex if it can be. */ + // it can't + /*! Cast the Interface0D in ViewVertex if it can be. */ + virtual ViewVertex * castToViewVertex(){ + return this; + } + + /*! Cast the Interface0D in TVertex if it can be. */ + virtual TVertex * castToTVertex(){ + return this; + } + +private: + SVertex *_FrontSVertex; + SVertex *_BackSVertex; + directedViewEdge _FrontEdgeA; + directedViewEdge _FrontEdgeB; + directedViewEdge _BackEdgeA; + directedViewEdge _BackEdgeB; + Id _Id; // id to identify t vertices . these id will be negative in order not to be mixed with NonTVertex ids. + edge_pointers_container _sortedEdges; // the list of the four ViewEdges, ordered in CCW order (in the image plan) + + +public: + /*! Default constructor.*/ + inline TVertex() : ViewVertex(Nature::T_VERTEX) + { + _FrontSVertex = 0; + _BackSVertex = 0; + _FrontEdgeA.first = 0; + _FrontEdgeB.first = 0; + _BackEdgeA.first = 0; + _BackEdgeB.first = 0; + + } + + inline TVertex(SVertex *svFront, SVertex *svBack) + : ViewVertex(Nature::T_VERTEX) + { + _FrontSVertex = svFront; + _BackSVertex = svBack; + _FrontEdgeA.first = 0; + _FrontEdgeB.first = 0; + _BackEdgeA.first = 0; + _BackEdgeB.first = 0; + svFront->setViewVertex(this); + svBack->setViewVertex(this); + } + +protected: + /*! Copy constructor. */ + inline TVertex(TVertex& iBrother) + : ViewVertex(iBrother) + { + _FrontSVertex = iBrother._FrontSVertex; + _BackSVertex = iBrother._BackSVertex; + _FrontEdgeA = iBrother._FrontEdgeA; + _FrontEdgeB = iBrother._FrontEdgeB; + _BackEdgeA = iBrother._BackEdgeA; + _BackEdgeB = iBrother._BackEdgeB; + _sortedEdges = iBrother._sortedEdges; + } + + /*! Cloning method. */ + virtual ViewVertex * duplicate() + { + TVertex *clone = new TVertex(*this); + return clone; + } + +public: + /* accessors */ + /*! Returns the SVertex that is closer to the viewpoint. */ + inline SVertex *frontSVertex() {return _FrontSVertex;} + /*! Returns the SVertex that is further away from the viewpoint. */ + inline SVertex *backSVertex() {return _BackSVertex;} + inline directedViewEdge& frontEdgeA() {return _FrontEdgeA;} + inline directedViewEdge& frontEdgeB() {return _FrontEdgeB;} + inline directedViewEdge& backEdgeA() {return _BackEdgeA;} + inline directedViewEdge& backEdgeB() {return _BackEdgeB;} + + /* modifiers */ + /*! Sets the SVertex that is closer to the viewpoint. */ + inline void setFrontSVertex(SVertex *iFrontSVertex) {_FrontSVertex = iFrontSVertex;_FrontSVertex->setViewVertex(this);} + /*! Sets the SVertex that is further away from the viewpoint. */ + inline void setBackSVertex(SVertex *iBackSVertex) {_BackSVertex = iBackSVertex;_BackSVertex->setViewVertex(this);} + void setFrontEdgeA(ViewEdge *iFrontEdgeA, bool incoming=true); + void setFrontEdgeB(ViewEdge *iFrontEdgeB, bool incoming=true) ; + void setBackEdgeA(ViewEdge *iBackEdgeA, bool incoming=true); + void setBackEdgeB(ViewEdge *iBackEdgeB, bool incoming=true) ; + /*! Sets the Id. */ + inline void setId(const Id& iId) {_Id = iId;} + + /*! Returns the SVertex (among the 2) belonging to the FEdge iFEdge */ + inline SVertex * getSVertex(FEdge *iFEdge) + { + const vector<FEdge*>& vfEdges = _FrontSVertex->fedges(); + vector<FEdge*>::const_iterator fe,fend; + for(fe=vfEdges.begin(),fend=vfEdges.end(); + fe!=fend; + fe++) + { + if((*fe) == iFEdge) + return _FrontSVertex; + } + + const vector<FEdge*>& vbEdges = _BackSVertex->fedges(); + for(fe=vbEdges.begin(),fend=vbEdges.end(); + fe!=fend; + fe++) + { + if((*fe) == iFEdge) + return _BackSVertex; + } + return 0; + } + + virtual void Replace(ViewEdge *iOld, ViewEdge *iNew); + + /*! returns the mate edge of iEdgeA. + * For example, if iEdgeA is frontEdgeA, + * then frontEdgeB is returned. If iEdgeA is + * frontEdgeB then frontEdgeA is returned. + * Same for back edges + */ + virtual ViewEdge * mate(ViewEdge* iEdgeA) + { + if(iEdgeA == _FrontEdgeA.first) + return _FrontEdgeB.first; + if(iEdgeA == _FrontEdgeB.first) + return _FrontEdgeA.first; + if(iEdgeA == _BackEdgeA.first) + return _BackEdgeB.first; + if(iEdgeA == _BackEdgeB.first) + return _BackEdgeA.first; + return 0; + } + + /* iterators access */ + virtual edge_iterator edges_begin(); + virtual const_edge_iterator edges_begin() const; + virtual edge_iterator edges_end(); + virtual const_edge_iterator edges_end() const; + virtual edge_iterator edges_iterator(ViewEdge *iEdge); + virtual const_edge_iterator edges_iterator(ViewEdge *iEdge) const; + + /*! Returns an iterator over the ViewEdges that goes to or comes from + * this ViewVertex pointing to the first ViewEdge of the list. + * The orientedViewEdgeIterator allows to iterate in CCW order over these ViewEdges + * and to get the orientation for each ViewEdge (incoming/outgoing). + */ + virtual ViewVertexInternal::orientedViewEdgeIterator edgesBegin() ; + /*! Returns an orientedViewEdgeIterator over the ViewEdges around this ViewVertex, + * pointing after the last ViewEdge. + */ + virtual ViewVertexInternal::orientedViewEdgeIterator edgesEnd() ; + /*! Returns an orientedViewEdgeIterator pointing to the ViewEdge + * given as argument. + */ + virtual ViewVertexInternal::orientedViewEdgeIterator edgesIterator(ViewEdge *iEdge) ; +}; + + + /**********************************/ + /* */ + /* */ + /* NonTVertex */ + /* */ + /* */ + /**********************************/ + + +// (non T vertex) +/*! View vertex for corners, cusps, etc... + * Associated to a single SVertex. + * Can be associated to 2 or several view edges + */ +class LIB_VIEW_MAP_EXPORT NonTVertex : public ViewVertex +{ +public: + typedef vector<directedViewEdge> edges_container; + +public: // Implementation of Interface0D + + /*! Returns the string "ViewVertex" .*/ + virtual string getExactTypeName() const { + return "NonTVertex"; + } + + // Data access methods + /*! Returns the 3D x coordinate of the vertex .*/ + virtual real getX() const { + return _SVertex->point3D().x(); + } + /*! Returns the 3D y coordinate of the vertex .*/ + virtual real getY() const { + return _SVertex->point3D().y(); + } + + /*! Returns the 3D z coordinate of the vertex .*/ + virtual real getZ() const { + return _SVertex->point3D().z(); + } + + /*! Returns the 3D point. */ + virtual Vec3f getPoint3D() const { + return _SVertex->getPoint3D(); + } + + /*! Returns the projected 3D x coordinate of the vertex .*/ + virtual real getProjectedX() const { + return _SVertex->point2D().x(); + } + + /*! Returns the projected 3D y coordinate of the vertex .*/ + virtual real getProjectedY() const { + return _SVertex->point2D().y(); + } + + /*! Returns the projected 3D z coordinate of the vertex .*/ + virtual real getProjectedZ() const { + return _SVertex->point2D().z(); + } + + /*! Returns the 2D point. */ + virtual Vec2f getPoint2D() const { + return _SVertex->getPoint2D(); + } + + /*! Returns the Id of the vertex .*/ + virtual Id getId() const { + return _SVertex->getId(); + } + + /*! Cast the Interface0D in SVertex if it can be. */ + virtual SVertex * castToSVertex(){ + return _SVertex; + } + + /*! Cast the Interface0D in ViewVertex if it can be. */ + virtual ViewVertex * castToViewVertex(){ + return this; + } + + /*! Cast the Interface0D in NonTVertex if it can be. */ + virtual NonTVertex * castToNonTVertex(){ + return this; + } + +private: + SVertex *_SVertex; + edges_container _ViewEdges; +public: + /*! Default constructor.*/ + inline NonTVertex() : ViewVertex(Nature::NON_T_VERTEX) { _SVertex = 0; } + /*! Builds a NonTVertex from a SVertex. */ + inline NonTVertex(SVertex* iSVertex) : ViewVertex(Nature::NON_T_VERTEX) + { + _SVertex = iSVertex; + _SVertex->setViewVertex(this); + } +protected: + /*! Copy constructor. */ + inline NonTVertex(NonTVertex& iBrother) + : ViewVertex(iBrother) + { + _SVertex = iBrother._SVertex; + _SVertex->setViewVertex(this); + _ViewEdges = iBrother._ViewEdges; + } + /*! Cloning method. */ + virtual ViewVertex * duplicate() + { + NonTVertex *clone = new NonTVertex(*this); + return clone; + } +public: + /*! destructor. */ + virtual ~NonTVertex() {} + + /* accessors */ + /*! Returns the SVertex on top of which this NonTVertex is built. */ + inline SVertex * svertex() {return _SVertex;} + inline edges_container& viewedges() {return _ViewEdges;} + + /* modifiers */ + /*! Sets the SVertex on top of which this NonTVertex is built. */ + inline void setSVertex(SVertex *iSVertex) {_SVertex = iSVertex;_SVertex->setViewVertex(this);} + inline void setViewEdges(const vector<directedViewEdge>& iViewEdges) {_ViewEdges = iViewEdges;} + void AddIncomingViewEdge(ViewEdge * iVEdge) ; + void AddOutgoingViewEdge(ViewEdge * iVEdge) ; + inline void AddViewEdge(ViewEdge * iVEdge, bool incoming=true) { + if(incoming) + AddIncomingViewEdge(iVEdge); + else + AddOutgoingViewEdge(iVEdge); + } + /* Replaces old edge by new edge */ + virtual void Replace(ViewEdge *iOld, ViewEdge *iNew) + { + + edges_container::iterator insertedve; + for(edges_container::iterator ve=_ViewEdges.begin(),vend=_ViewEdges.end(); + ve!=vend; + ve++) + { + if((ve)->first == iOld) + { + insertedve = _ViewEdges.insert(ve, directedViewEdge(iNew, ve->second));// inserts e2 before ve. + // returns an iterator pointing toward e2. ve is invalidated. + // we want to remove e1, but we can't use ve anymore: + insertedve++; // insertedve points now to e1 + _ViewEdges.erase(insertedve); + return; + } + } + } + + + /* iterators access */ + virtual edge_iterator edges_begin(); + virtual const_edge_iterator edges_begin() const; + virtual edge_iterator edges_end(); + virtual const_edge_iterator edges_end() const; + virtual edge_iterator edges_iterator(ViewEdge *iEdge); + virtual const_edge_iterator edges_iterator(ViewEdge *iEdge) const; + + /*! Returns an iterator over the ViewEdges that goes to or comes from + * this ViewVertex pointing to the first ViewEdge of the list. + * The orientedViewEdgeIterator allows to iterate in CCW order over these ViewEdges + * and to get the orientation for each ViewEdge (incoming/outgoing). + */ + virtual ViewVertexInternal::orientedViewEdgeIterator edgesBegin() ; + /*! Returns an orientedViewEdgeIterator over the ViewEdges around this ViewVertex, + * pointing after the last ViewEdge. + */ + virtual ViewVertexInternal::orientedViewEdgeIterator edgesEnd() ; + /*! Returns an orientedViewEdgeIterator pointing to the ViewEdge + * given as argument. + */ + virtual ViewVertexInternal::orientedViewEdgeIterator edgesIterator(ViewEdge *iEdge) ; +}; + + /**********************************/ + /* */ + /* */ + /* ViewEdge */ + /* */ + /* */ + /**********************************/ + +/* Geometry(normals...) + Nature of edges + 2D spaces (1or2, material, z...) + Parent Shape + 3D Shading, material + Importance + Occluders + */ +class ViewShape; + +namespace ViewEdgeInternal { + template<class Traits> class edge_iterator_base ; + template<class Traits> class fedge_iterator_base ; + template<class Traits> class vertex_iterator_base ; +} // end of namespace ViewEdgeInternal + +/*! Class defining a ViewEdge. A ViewEdge in an edge + * of the image graph. it connnects two ViewVertex. + * It is made by connecting a set of FEdges. + */ +class LIB_VIEW_MAP_EXPORT ViewEdge : public Interface1D +{ +public: // Implementation of Interface0D + + /*! Returns the string "ViewEdge" .*/ + virtual string getExactTypeName() const { + return "ViewEdge"; + } + + // Data access methods + /*! Returns the Id of the vertex .*/ + virtual Id getId() const { + return _Id; + } + + /*! Returns the nature of the ViewEdge. */ + virtual Nature::EdgeNature getNature() const { + return _Nature; + } + +public: + + typedef SVertex vertex_type; + friend class ViewShape; + // for ViewEdge iterator + typedef ViewEdgeInternal::edge_iterator_base<Nonconst_traits<ViewEdge*> > edge_iterator; + typedef ViewEdgeInternal::edge_iterator_base<Const_traits<ViewEdge*> > const_edge_iterator; + // for fedge iterator + typedef ViewEdgeInternal::fedge_iterator_base<Nonconst_traits<FEdge*> > fedge_iterator; + typedef ViewEdgeInternal::fedge_iterator_base<Const_traits<FEdge*> > const_fedge_iterator; + // for svertex iterator + typedef ViewEdgeInternal::vertex_iterator_base<Nonconst_traits<SVertex*> > vertex_iterator; + typedef ViewEdgeInternal::vertex_iterator_base<Const_traits<SVertex*> > const_vertex_iterator; +private: + + ViewVertex * __A; // edge starting vertex + ViewVertex * __B; // edge ending vertex + Nature::EdgeNature _Nature; // nature of view edge + ViewShape *_Shape; // shape to which the view edge belongs + FEdge * _FEdgeA; // first edge of the embedded fedges chain + FEdge * _FEdgeB; // last edge of the embedded fedges chain + Id _Id; + unsigned _ChainingTimeStamp; + ViewShape *_aShape; // The silhouette view edge separates 2 2D spaces. The one on the left is + // necessarly the Shape _Shape (the one to which this edge belongs to) + // and _aShape is the one on its right // NON GERE PAR LE COPY CONSTRUCTEUR + int _qi; + vector<ViewShape*> _Occluders; + + // tmp + Id * _splittingId; + +public: + /*! A field that can be used by the user to store any data. + * This field must be reseted afterwards using ResetUserData(). + */ + void * userdata; + /*! Default constructor.*/ + inline ViewEdge() { + __A=0; + __B=0; + _FEdgeA = 0; + _FEdgeB = 0; + _ChainingTimeStamp = 0; + _qi = 0; + _aShape=0; + userdata = 0; + _splittingId = 0; + } + inline ViewEdge(ViewVertex* iA, ViewVertex *iB) + { + __A = iA; + __B = iB; + _FEdgeA = 0; + _FEdgeB = 0; + _Shape = 0; + _ChainingTimeStamp = 0; + _aShape = 0; + _qi = 0; + userdata = 0; + _splittingId = 0; + } + inline ViewEdge(ViewVertex* iA, ViewVertex *iB, FEdge *iFEdgeA) + { + __A = iA; + __B = iB; + _FEdgeA = iFEdgeA; + _FEdgeB = 0; + _Shape = 0; + _ChainingTimeStamp = 0; + _aShape = 0; + _qi = 0; + userdata = 0; + _splittingId = 0; + } + inline ViewEdge(ViewVertex* iA, ViewVertex *iB, FEdge *iFEdgeA, FEdge *iFEdgeB, ViewShape *iShape) + { + __A = iA; + __B = iB; + _FEdgeA = iFEdgeA; + _FEdgeB = iFEdgeB; + _Shape = iShape; + _ChainingTimeStamp = 0; + _aShape = 0; + _qi = 0; + userdata = 0; + _splittingId = 0; + UpdateFEdges(); // tells every FEdge between iFEdgeA and iFEdgeB that this is theit ViewEdge + } + +//soc protected: + + /*! Copy constructor. */ + inline ViewEdge(ViewEdge& iBrother) + { + __A = iBrother.__A; + __B = iBrother.__B; + _FEdgeA = iBrother._FEdgeA; + _FEdgeB = iBrother._FEdgeB; + _Nature = iBrother._Nature; + _Shape = 0; + _Id = iBrother._Id; + _ChainingTimeStamp = iBrother._ChainingTimeStamp; + _aShape = iBrother._aShape; + _qi = iBrother._qi; + _splittingId = 0; + iBrother.userdata = this; + userdata = 0; + } + /*! Cloning method. */ + virtual ViewEdge * duplicate() + { + ViewEdge *clone = new ViewEdge(*this); + return clone; + } + +public: + /*! Destructor. */ + virtual ~ViewEdge() + { + // if(0 != _aFace) + // { + // delete _aFace; + // _aFace = 0; + // } + // only the last splitted deletes this id + if(_splittingId){ + if(*_splittingId == _Id) + delete _splittingId; + } + } + + /* accessors */ + /*! Returns the first ViewVertex. */ + inline ViewVertex* A() {return __A;} + /*! Returns the second ViewVertex. */ + inline ViewVertex* B() {return __B;} + /*! Returns the first FEdge that constitues this ViewEdge. */ + inline FEdge* fedgeA() {return _FEdgeA;} + /*! Returns the last FEdge that constitues this ViewEdge. */ + inline FEdge* fedgeB() {return _FEdgeB;} + /*! Returns the ViewShape to which this ViewEdge belongs to .*/ + inline ViewShape * viewShape() {return _Shape;} + /*! Returns the shape that is occluded by the ViewShape + * to which this ViewEdge belongs to. If no object is occluded, + * 0 is returned. + * \return The occluded ViewShape. + */ + inline ViewShape * aShape() {return _aShape;} + /*! Tells whether this ViewEdge forms a closed loop + * or not. + */ + inline bool isClosed() + { + if(__B == 0) + return true; + return false; + } + /*! Returns the time stamp of this ViewEdge. */ + inline unsigned getChainingTimeStamp() {return _ChainingTimeStamp;} + inline const ViewShape * aShape() const {return _aShape;} + inline const ViewShape * bShape() const {return _Shape;} + inline vector<ViewShape*>& occluders() {return _Occluders;} + inline Id * splittingId() {return _splittingId;} + + /* modifiers */ + /*! Sets the first ViewVertex of the ViewEdge. */ + inline void setA(ViewVertex* iA) { __A = iA; } + /*! Sets the last ViewVertex of the ViewEdge. */ + inline void setB(ViewVertex* iB) { __B = iB; } + /*! Sets the nature of the ViewEdge. */ + inline void setNature(Nature::EdgeNature iNature) { _Nature = iNature; } + /*! Sets the first FEdge of the ViewEdge. */ + inline void setFEdgeA(FEdge* iFEdge) { _FEdgeA = iFEdge; } + /*! Sets the last FEdge of the ViewEdge. */ + inline void setFEdgeB(FEdge* iFEdge) { _FEdgeB = iFEdge; } + /*! Sets the ViewShape to which this ViewEdge belongs to.*/ + inline void setShape(ViewShape *iVShape) + { + _Shape = iVShape; + } + /*! Sets the ViewEdge id. */ + inline void setId(const Id& id) {_Id = id;} + /*! Sets Viewedge to this for all embedded fedges */ + void UpdateFEdges(); + /*! Sets the occluded ViewShape */ + inline void setaShape(ViewShape * iShape) {_aShape = iShape;} + /*! Sets the quantitative invisibility value. */ + inline void setQI(int qi) {_qi = qi;} + /*! Sets the time stamp value. */ + inline void setChainingTimeStamp(unsigned ts) {_ChainingTimeStamp = ts;} + inline void AddOccluder(ViewShape *iShape) {_Occluders.push_back(iShape);} + inline void setSplittingId(Id * id) {_splittingId = id;} + + /* stroke interface definition */ + inline bool intersect_2d_area(const Vec2r& iMin, const Vec2r& iMax) const + { + // parse edges to check if one of them is intersection the region: + FEdge * current = _FEdgeA; + do + { + if(GeomUtils::intersect2dSeg2dArea(iMin,iMax, + Vec2r(current->vertexA()->point2D()[0],current->vertexA()->point2D()[1]), + Vec2r(current->vertexB()->point2D()[0],current->vertexB()->point2D()[1]))) + + return true; + current = current->nextEdge(); + }while((current != 0) && (current != _FEdgeA)); + + return false; + } + inline bool include_in_2d_area(const Vec2r& iMin, const Vec2r& iMax) const + { + // parse edges to check if all of them are intersection the region: + FEdge * current = _FEdgeA; + + do + { + if(!GeomUtils::include2dSeg2dArea(iMin,iMax, + Vec2r(current->vertexA()->point2D()[0],current->vertexA()->point2D()[1]), + Vec2r(current->vertexB()->point2D()[0],current->vertexB()->point2D()[1]))) + return false; + current = current->nextEdge(); + }while((current != 0) && (current != _FEdgeA)); + + return true; + } + + /* Information access interface */ + + //inline Nature::EdgeNature viewedge_nature() const {return getNature();} + //float viewedge_length() const ; + /*! Returns the 2D length of the Viewedge. */ + real getLength2D() const; + //inline Material material() const {return _FEdgeA->vertexA()->shape()->material();} + inline int qi() const {return _qi;} + inline occluder_container::const_iterator occluders_begin() const {return _Occluders.begin();} + inline occluder_container::const_iterator occluders_end() const {return _Occluders.end();} + inline int occluders_size() const {return _Occluders.size();} + inline bool occluders_empty() const {return _Occluders.empty();} + inline const Polygon3r& occludee() const {return (_FEdgeA->aFace());} + inline const SShape * occluded_shape() const ; + inline const bool occludee_empty() const {if(_aShape == 0) return true; return false;} + //inline real z_discontinuity(int iCombination = 0) const ; + inline Id shape_id() const {return _FEdgeA->vertexA()->shape()->getId();} + inline const SShape * shape() const {return _FEdgeA->vertexA()->shape();} + inline float shape_importance() const {return _FEdgeA->shape_importance();} + + /* iterators access */ + // view edge iterator + edge_iterator ViewEdge_iterator(); + const_edge_iterator ViewEdge_iterator() const; + // feature edge iterator + fedge_iterator fedge_iterator_begin(); + const_fedge_iterator fedge_iterator_begin() const; + fedge_iterator fedge_iterator_last(); + const_fedge_iterator fedge_iterator_last() const; + fedge_iterator fedge_iterator_end(); + const_fedge_iterator fedge_iterator_end() const; + // embedding vertex iterator + const_vertex_iterator vertices_begin() const; + vertex_iterator vertices_begin(); + const_vertex_iterator vertices_last() const; + vertex_iterator vertices_last(); + const_vertex_iterator vertices_end() const; + vertex_iterator vertices_end(); + + // Iterator access (Interface1D) + /*! Returns an Interface0DIterator to iterate over + * the SVertex constituing the embedding of this ViewEdge. + * The returned Interface0DIterator points to the first + * SVertex of the ViewEdge. + */ + virtual Interface0DIterator verticesBegin(); + /*! Returns an Interface0DIterator to iterate over + * the SVertex constituing the embedding of this ViewEdge. + * The returned Interface0DIterator points after the last + * SVertex of the ViewEdge. + */ + virtual Interface0DIterator verticesEnd(); + + /*! Returns an Interface0DIterator to iterate over + * the points of this ViewEdge at a given resolution. + * The returned Interface0DIterator points on the first + * Point of the ViewEdge. + * \param t + * the sampling value. + */ + virtual Interface0DIterator pointsBegin(float t=0.f); + /*! Returns an Interface0DIterator to iterate over + * the points of this ViewEdge at a given resolution. + * The returned Interface0DIterator points after the last + * Point of the ViewEdge. + * \param t + * the sampling value. + */ + virtual Interface0DIterator pointsEnd(float t=0.f); +}; + + + + /**********************************/ + /* */ + /* */ + /* ViewShape */ + /* */ + /* */ + /**********************************/ + +/*! Class gathering the elements of the ViewMap (ViewVertex, ViewEdge) + * that are issued from the same input shape. + */ +class LIB_VIEW_MAP_EXPORT ViewShape +{ +private: + vector<ViewVertex*> _Vertices; + vector<ViewEdge*> _Edges; + SShape * _SShape; + + +public: + /*! A field that can be used by the user to store any data. + * This field must be reseted afterwards using ResetUserData(). + */ + void* userdata; + /*! Default constructor.*/ + inline ViewShape() { userdata = 0; _SShape = 0;} + /*! Builds a ViewShape from a SShape. */ + inline ViewShape(SShape *iSShape) {userdata = 0; _SShape = iSShape;}//_SShape->setViewShape(this);} + /*! Copy constructor. */ + inline ViewShape(ViewShape& iBrother) + { + userdata = 0; + vector<ViewVertex*>::iterator vv,vvend; + vector<ViewEdge*>::iterator ve, veend; + + _SShape = iBrother._SShape; + + vector<ViewVertex*>& vvertices = iBrother.vertices(); + // duplicate vertices + for(vv=vvertices.begin(), vvend=vvertices.end(); + vv!=vvend; + vv++) + { + ViewVertex * newVertex = (*vv)->duplicate(); + AddVertex(newVertex); + } + + vector<ViewEdge*>& vvedges = iBrother.edges(); + // duplicate edges + for(ve=vvedges.begin(), veend=vvedges.end(); + ve!=veend; + ve++) + { + ViewEdge * newEdge = (*ve)->duplicate(); + AddEdge(newEdge); // here the shape is set as the edge's shape + } + + //------------------------- + // remap edges in vertices: + //------------------------- + for(vv=_Vertices.begin(), vvend=_Vertices.end(); + vv!=vvend; + vv++) + { + switch((*vv)->getNature()) + { + case Nature::T_VERTEX: + { + TVertex *v = (TVertex*)(*vv); + ViewEdge *veFrontA = (ViewEdge*)(v)->frontEdgeA().first->userdata; + ViewEdge *veFrontB = (ViewEdge*)(v)->frontEdgeB().first->userdata; + ViewEdge *veBackA = (ViewEdge*)(v)->backEdgeA().first->userdata; + ViewEdge *veBackB = (ViewEdge*)(v)->backEdgeB().first->userdata; + + v->setFrontEdgeA(veFrontA, v->frontEdgeA().second); + v->setFrontEdgeB(veFrontB, v->frontEdgeB().second); + v->setBackEdgeA(veBackA, v->backEdgeA().second); + v->setBackEdgeB(veBackB, v->backEdgeB().second); + } + break; + case Nature::NON_T_VERTEX: + { + NonTVertex * v = (NonTVertex*)(*vv); + vector<ViewVertex::directedViewEdge>& vedges = (v)->viewedges(); + vector<ViewVertex::directedViewEdge> newEdges; + for(vector<ViewVertex::directedViewEdge>::iterator ve=vedges.begin(), veend=vedges.end(); + ve!=veend; + ve++) + { + ViewEdge *current = (ViewEdge*)((ve)->first)->userdata; + newEdges.push_back(ViewVertex::directedViewEdge(current, ve->second)); + } + (v)->setViewEdges(newEdges); + } + break; + default: + ; + } + } + + //------------------------------------- + // remap vertices in edges: + //------------------------------------- + for(ve=_Edges.begin(),veend=_Edges.end(); + ve!=veend; + ve++) + { + (*ve)->setA((ViewVertex*)((*ve)->A()->userdata)); + (*ve)->setB((ViewVertex*)((*ve)->B()->userdata)); + //--------------------------------------- + // Update all embedded FEdges + //--------------------------------------- + (*ve)->UpdateFEdges(); + } + + + // reset all brothers userdata to NULL: + //------------------------------------- + //--------- + // vertices + //--------- + for(vv=vvertices.begin(),vvend=vvertices.end(); + vv!=vvend; + vv++) + { + (*vv)->userdata = NULL; + } + + //------ + // edges + //------ + for(ve=vvedges.begin(),veend=vvedges.end(); + ve!=veend; + ve++) + { + (*ve)->userdata = NULL; + } + } + + /*! Cloning method. */ + virtual ViewShape * duplicate() + { + ViewShape *clone = new ViewShape(*this); + return clone; + } + + /*! Destructor. */ + virtual ~ViewShape(); + + /* splits a view edge into several view edges. + * fe + * The FEdge that gets splitted + * iViewVertices + * The view vertices corresponding to the different intersections for the edge fe. + * This list need to be sorted such as the first view vertex is the + * farther away from fe->vertexA. + * ioNewEdges + * The feature edges that are newly created (the initial edges are not + * included) are added to this list. + * ioNewViewEdges + * The view edges that are newly created (the initial edges are not + * included) are added to this list. + */ + inline void SplitEdge(FEdge *fe, + const vector<TVertex*>& iViewVertices, + vector<FEdge*>& ioNewEdges, + vector<ViewEdge*>& ioNewViewEdges); + /* accessors */ + /*! Returns the SShape on top of which this ViewShape is built. */ + inline SShape * sshape() {return _SShape;} + /*! Returns the SShape on top of which this ViewShape is built. */ + inline const SShape * sshape() const {return _SShape;} + /*! Returns the list of ViewVertex contained in this ViewShape. */ + inline vector<ViewVertex*>& vertices() {return _Vertices;} + /*! Returns the list of ViewEdge contained in this ViewShape. */ + inline vector<ViewEdge*>& edges() {return _Edges;} + /*! Returns the ViewShape id. */ + inline Id getId() const {return _SShape->getId();} + + /* modifiers */ + /*! Sets the SShape on top of which the ViewShape is built. */ + inline void setSShape(SShape* iSShape) {_SShape = iSShape;} + /*! Sets the list of ViewVertex contained in this ViewShape. */ + inline void setVertices(const vector<ViewVertex*>& iVertices) {_Vertices = iVertices;} + /*! Sets the list of ViewEdge contained in this ViewShape. */ + inline void setEdges(const vector<ViewEdge*>& iEdges) {_Edges = iEdges;} + /*! Adds a ViewVertex to the list. */ + inline void AddVertex(ViewVertex *iVertex) + { + _Vertices.push_back(iVertex); + //_SShape->AddNewVertex(iVertex->svertex()); + } + /*! Adds a ViewEdge to the list */ + inline void AddEdge(ViewEdge *iEdge) + { + _Edges.push_back(iEdge); + iEdge->setShape(this); + //_SShape->AddNewEdge(iEdge->fedge()); + } + + /* removes the view edge iViewEdge in the + * View Shape and the associated FEdge chain entry + * in the underlying SShape + */ + void RemoveEdge(ViewEdge * iViewEdge); + + /* removes the view vertex iViewVertex in the + * View Shape. + */ + void RemoveVertex(ViewVertex * iViewVertex); +}; + + + +/* + + ############################################# + ############################################# + ############################################# + ###### ###### + ###### I M P L E M E N T A T I O N ###### + ###### ###### + ############################################# + ############################################# + ############################################# + +*/ +/* for inline functions */ + +void ViewShape::SplitEdge(FEdge *fe, + const vector<TVertex*>& iViewVertices, + vector<FEdge*>& ioNewEdges, + vector<ViewEdge*>& ioNewViewEdges) +{ + ViewEdge *vEdge = fe->viewedge(); + + + // We first need to sort the view vertices from farther to closer to fe->vertexA + + SVertex *sv, *sv2; + ViewVertex *vva, *vvb; + vector<TVertex*>::const_iterator vv, vvend; + for(vv=iViewVertices.begin(), vvend = iViewVertices.end(); + vv!=vvend; + vv++) + { + // Add the viewvertices to the ViewShape + AddVertex((*vv)); + + // retrieve the correct SVertex from the view vertex + //-------------------------------------------------- + sv = (*vv)->frontSVertex(); + sv2 = (*vv)->backSVertex(); + + if(sv->shape() != sv2->shape()) + { + if(sv->shape() != _SShape) + sv = sv2; + } + else + { + // if the shape is the same we can safely differ + // the two vertices using their ids: + if(sv->getId() != fe->vertexA()->getId()) + sv = sv2; + } + + vva = vEdge->A(); + vvb = vEdge->B(); + + // We split Fedge AB into AA' and A'B. A' and A'B are created. + // AB becomes (address speaking) AA'. B is updated. + //-------------------------------------------------- + SShape * shape = fe->shape(); + + // a new edge, A'B is created. + FEdge *newEdge = shape->SplitEdgeIn2(fe, sv); + + ioNewEdges.push_back(newEdge); + ViewEdge *newVEdge; + + if((vva == 0) || (vvb == 0)) // that means we're dealing with a closed viewedge (loop) + { + // remove the chain that was starting by the fedge A of vEdge (which is different from fe !!!!) + shape->RemoveEdgeFromChain(vEdge->fedgeA()); + // we set + vEdge->setA(*vv); + vEdge->setB(*vv); + vEdge->setFEdgeA(newEdge); + //FEdge *previousEdge = newEdge->previousEdge(); + vEdge->setFEdgeB(fe); + newVEdge = vEdge; + vEdge->fedgeA()->setViewEdge(newVEdge); + } + else + { + + // while we create the view edge, it updates the "ViewEdge" pointer + // of every underlying FEdges to this. + newVEdge = new ViewEdge((*vv),vvb);//, newEdge, vEdge->fedgeB()); + newVEdge->setNature((fe)->getNature()); + newVEdge->setFEdgeA(newEdge); + //newVEdge->setFEdgeB(fe); + // If our original viewedge is made of one FEdge, + // then + if((vEdge->fedgeA() == vEdge->fedgeB()) || (fe == vEdge->fedgeB())) + newVEdge->setFEdgeB(newEdge); + else + newVEdge->setFEdgeB(vEdge->fedgeB()); //MODIF + + Id * newId = vEdge->splittingId(); + if(newId == 0){ + newId = new Id(vEdge->getId()); + vEdge->setSplittingId(newId); + } + newId->setSecond(newId->getSecond()+1); + newVEdge->setId(*newId); + newVEdge->setSplittingId(newId); + // Id id(vEdge->getId().getFirst(), vEdge->getId().getSecond()+1); + // newVEdge->setId(vEdge->getId()); + // vEdge->setId(id); + + AddEdge(newVEdge); // here this shape is set as the edge's shape + + // add new edge to the list of new edges passed as argument: + ioNewViewEdges.push_back(newVEdge); + + + + if(0 != vvb) + vvb->Replace((vEdge), newVEdge); + + // we split the view edge: + vEdge->setB((*vv)); + vEdge->setFEdgeB(fe); //MODIF + + // Update fedges so that they point to the new viewedge: + newVEdge->UpdateFEdges(); + + } + // check whether this vertex is a front vertex or a back + // one + + if(sv == (*vv)->frontSVertex()) + { + // -- View Vertex A' -- + (*vv)->setFrontEdgeA(vEdge, true); + (*vv)->setFrontEdgeB(newVEdge, false); + } + else + { + // -- View Vertex A' -- + (*vv)->setBackEdgeA(vEdge, true); + (*vv)->setBackEdgeB(newVEdge, false); + } + } +} + + /**********************************/ + /* */ + /* */ + /* ViewEdge */ + /* */ + /* */ + /**********************************/ + + +// inline Vec3r ViewEdge::orientation2d(int iCombination) const +// { +// return edge_orientation2d_function<ViewEdge>(*this, iCombination); +// } + +// inline Vec3r ViewEdge::orientation3d(int iCombination) const +// { +// return edge_orientation3d_function<ViewEdge>(*this, iCombination); +// } + +// inline real ViewEdge::z_discontinuity(int iCombination) const +// { +// return z_discontinuity_edge_function<ViewEdge>(*this, iCombination); +// } + +// inline float ViewEdge::local_average_depth(int iCombination ) const +// { +// return local_average_depth_edge_function<ViewEdge>(*this, iCombination); +// } + +// inline float ViewEdge::local_depth_variance(int iCombination) const +// { +// return local_depth_variance_edge_function<ViewEdge>(*this, iCombination); +// } + +// inline real ViewEdge::local_average_density(float sigma, int iCombination) const +// { +// return density_edge_function<ViewEdge>(*this, iCombination); +// } + +inline const SShape * ViewEdge::occluded_shape() const +{ + if(0 == _aShape) + return 0; + return _aShape->sshape(); +} + +// inline Vec3r ViewEdge::curvature2d_as_vector(int iCombination) const +// { +// return curvature2d_as_vector_edge_function<ViewEdge>(*this, iCombination); +// } + +// inline real ViewEdge::curvature2d_as_angle(int iCombination) const +// { +// return curvature2d_as_angle_edge_function<ViewEdge>(*this, iCombination); +// } + + +#endif // VIEWMAP_H diff --git a/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h b/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h new file mode 100755 index 00000000000..31abefbfb97 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMapAdvancedIterators.h @@ -0,0 +1,691 @@ +// +// Filename : ViewMapAdvancedIterators.h +// Author(s) : Stephane Grabli +// Purpose : Iterators used to iterate over the various elements of the ViewMap +// These iterators can't be exported to python. +// Date of creation : 01/07/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VIEWMAPADVANCEDITERATORS_H +# define VIEWMAPADVANCEDITERATORS_H + +#include "ViewMap.h" +#include "../system/Iterator.h" //soc + + /**********************************/ + /* */ + /* */ + /* ViewMap */ + /* */ + /* */ + /**********************************/ + + /**********************************/ + /* */ + /* */ + /* ViewVertex */ + /* */ + /* */ + /**********************************/ + +namespace ViewVertexInternal{ + + class edge_const_traits : public Const_traits< ::ViewVertex::directedViewEdge> { + public: + typedef vector< ::ViewVertex::directedViewEdge> edges_container; + typedef edges_container::const_iterator edges_container_iterator ; + typedef vector< ::ViewVertex::directedViewEdge*> edge_pointers_container; + typedef edge_pointers_container::const_iterator edge_pointers_container_iterator ; + }; + class edge_nonconst_traits : public Nonconst_traits< ::ViewVertex::directedViewEdge> { + public: + typedef vector< ::ViewVertex::directedViewEdge> edges_container; + typedef edges_container::iterator edges_container_iterator ; + typedef vector< ::ViewVertex::directedViewEdge*> edge_pointers_container; + typedef edge_pointers_container::iterator edge_pointers_container_iterator ; + }; + +template<class Traits> + class edge_iterator_base : public IteratorBase<Traits,InputIteratorTag_Traits> + { + public: + typedef typename Traits::value_type value_type; + typedef typename Traits::difference_type difference_type; + typedef typename Traits::pointer pointer; + typedef typename Traits::reference reference; + typedef edge_iterator_base<Traits> Self; + typedef typename Traits::edges_container_iterator edges_container_iterator; + typedef typename Traits::edge_pointers_container_iterator edge_pointers_container_iterator; + typedef edge_iterator_base<edge_nonconst_traits> iterator; + typedef edge_iterator_base<edge_const_traits> const_iterator; + public: + friend class ViewVertex; + friend class TVertex; + friend class NonTVertex; + friend class ViewEdge; + friend class edge_iterator; + protected: + Nature::VertexNature _Nature; // the nature of the underlying vertex + // T vertex attributes + edge_pointers_container_iterator _tbegin; + edge_pointers_container_iterator _tend; + edge_pointers_container_iterator _tvertex_iter; + + // mutable value_type _tvertex_iter; + // value_type _feA; + // value_type _feB; + // value_type _beA; + // value_type _beB; + + // Non TVertex attributes + edges_container_iterator _begin; + edges_container_iterator _end; + edges_container_iterator _nontvertex_iter; + + typedef IteratorBase<Traits,InputIteratorTag_Traits> parent_class; + + public: + inline edge_iterator_base() : parent_class() {} + inline edge_iterator_base(Nature::VertexNature iNature) + : parent_class() + {_Nature = iNature;} + edge_iterator_base(const edge_iterator_base<edge_nonconst_traits>& iBrother) + : parent_class(iBrother) + { + _Nature = iBrother._Nature; + if(_Nature & Nature::T_VERTEX) + { + // _feA = iBrother._feA; + // _feB = iBrother._feB; + // _beA = iBrother._beA; + // _beB = iBrother._beB; + // _tvertex_iter = iBrother._tvertex_iter; + _tbegin = iBrother._tbegin; + _tend = iBrother._tend; + _tvertex_iter = iBrother._tvertex_iter; + } + else + { + _begin = iBrother._begin; + _end = iBrother._end; + _nontvertex_iter = iBrother._nontvertex_iter; + } + } + edge_iterator_base(const edge_iterator_base<edge_const_traits>& iBrother) + : parent_class(iBrother) + { + _Nature = iBrother._Nature; + if(_Nature & Nature::T_VERTEX) + { + // _feA = iBrother._feA; + // _feB = iBrother._feB; + // _beA = iBrother._beA; + // _beB = iBrother._beB; + // _tvertex_iter = iBrother._tvertex_iter; + _tbegin = iBrother._tbegin; + _tend = iBrother._tend; + _tvertex_iter = iBrother._tvertex_iter; + } + else + { + _begin = iBrother._begin; + _end = iBrother._end; + _nontvertex_iter = iBrother._nontvertex_iter; + } + } + virtual ~edge_iterator_base() {} + //protected://FIXME + public: + // inline edge_iterator_base(value_type ifeA, + // value_type ifeB, + // value_type ibeA, + // value_type ibeB, + // value_type iter) + // : parent_class() + // { + // _Nature = Nature::T_VERTEX; + // _feA = ifeA; + // _feB = ifeB; + // _beA = ibeA; + // _beB = ibeB; + // _tvertex_iter = iter; + // } + inline edge_iterator_base(edge_pointers_container_iterator begin, + edge_pointers_container_iterator end, + edge_pointers_container_iterator iter) + : parent_class() + { + _Nature = Nature::T_VERTEX; + _tbegin = begin; + _tend = end; + _tvertex_iter = iter; + } + inline edge_iterator_base(edges_container_iterator begin, + edges_container_iterator end, + edges_container_iterator iter) + : parent_class() + { + _Nature = Nature::NON_T_VERTEX; + _begin = begin; + _end = end; + _nontvertex_iter = iter; + } + + public: + + + virtual bool begin() const + { + if(_Nature & Nature::T_VERTEX) + return (_tvertex_iter == _tbegin); + //return (_tvertex_iter == _feA); + else + return (_nontvertex_iter == _begin); + } + virtual bool end() const + { + if(_Nature & Nature::T_VERTEX) + //return (_tvertex_iter.first == 0); + return (_tvertex_iter == _tend); + else + return (_nontvertex_iter == _end); + } + + // operators + virtual Self& operator++() // operator corresponding to ++i + { + increment(); + return *this; + } + virtual Self operator++(int) // opérateur correspondant à i++ + { // c.a.d qui renvoie la valeur *puis* incrémente. + Self tmp = *this; // C'est pour cela qu'on stocke la valeur + increment(); // dans un temporaire. + return tmp; + } + + // comparibility + virtual bool operator!=(const Self& b) const + { + if(_Nature & Nature::T_VERTEX) + return (_tvertex_iter != b._tvertex_iter); + else + return (_nontvertex_iter != b._nontvertex_iter); + } + + virtual bool operator==(const Self& b) const + {return !(*this != b);} + + // dereferencing + virtual reference operator*() const + { + if(_Nature & Nature::T_VERTEX) + //return _tvertex_iter; + return **_tvertex_iter; + else + return (*_nontvertex_iter); + } + virtual pointer operator->() const { return &(operator*());} + + protected: + inline void increment() + { + if(_Nature & Nature::T_VERTEX) + { + value_type tmp = (**_tvertex_iter); + ++_tvertex_iter; + value_type tmp2 = (**_tvertex_iter); + if(tmp2.first == tmp.first) + ++_tvertex_iter; + // // Hack to deal with cusp. the result of a cusp + // // is a TVertex having two identical viewedges. + // // In order to iterate properly, we chose to + // // to skip these last ones. + // if(_feB.first == _beA.first) + // { + // if(_feA.first == _beB.first) + // { + // _tvertex_iter.first = 0; + // return; + // } + // + // if(_tvertex_iter.first == _feA.first) + // _tvertex_iter.first = _beB.first; + // else if(_tvertex_iter.first == _beB.first) + // _tvertex_iter.first = 0; + // else + // _tvertex_iter.first = _feA.first; + // return; + // } + // if(_feA.first == _beB.first) + // { + // if(_feB.first == _beA.first) + // { + // _tvertex_iter.first = 0; + // return; + // } + // + // if(_tvertex_iter.first == _feB.first) + // _tvertex_iter.first = _beA.first; + // else if(_tvertex_iter.first == _beA.first) + // _tvertex_iter.first = 0; + // else + // _tvertex_iter.first = _feB.first; + // return; + // } + // // End of hack + // + // if(_tvertex_iter.first == _feA.first){ + // // we return bea or beb + // + // + // // choose one of them + // + // _tvertex_iter.first = _feB.first; + // return; + // } + // if(_tvertex_iter.first == _feB.first) + // { + // _tvertex_iter.first = _beA.first; + // return; + // } + // if(_tvertex_iter.first == _beA.first) + // { + // _tvertex_iter.first = _beB.first; + // return; + // } + // if(_tvertex_iter.first == _beB.first) + // { + // _tvertex_iter.first = 0; + // return; + // } + } + else + ++_nontvertex_iter; + } + }; + + } + /**********************************/ + /* */ + /* */ + /* ViewEdge */ + /* */ + /* */ + /**********************************/ + +namespace ViewEdgeInternal { + + /*!----------------------*/ + /*! Iterators definition */ + /*!----------------------*/ + template<class Traits> + class edge_iterator_base : public IteratorBase<Traits,BidirectionalIteratorTag_Traits> + { + public: + typedef typename Traits::value_type value_type; + typedef typename Traits::difference_type difference_type; + typedef typename Traits::pointer pointer; + typedef typename Traits::reference reference; + typedef edge_iterator_base<Traits> Self; + public: + mutable value_type _ViewEdge; + //friend class edge_iterator_base<Nonconst_traits<ViewEdge*> >; + //friend class edge_iterator_base<Const_traits<ViewEdge*> >; + value_type _first; + bool _orientation; + typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class; + + public: + friend class ViewEdge; + inline edge_iterator_base() + : parent_class() + {_orientation=true;_first=0;} + + inline edge_iterator_base(const edge_iterator_base<Nonconst_traits< ::ViewEdge*> >& iBrother) + : parent_class() + { + _ViewEdge = iBrother._ViewEdge; + _first = iBrother._first; + _orientation = iBrother._orientation; + } + + inline edge_iterator_base(const edge_iterator_base<Const_traits< ::ViewEdge*> >& iBrother) + : parent_class() + { + _ViewEdge = iBrother._ViewEdge; + _first = iBrother._first; + _orientation = iBrother._orientation; + } + + //protected://FIXME + public: + inline edge_iterator_base(value_type iEdge, bool orientation = true) + : parent_class() + { + _ViewEdge = iEdge; + _first = iEdge; + _orientation = orientation; + } + + + public: + virtual Self* clone() const + { + return new edge_iterator_base(*this); + } + virtual ~edge_iterator_base() {} + + public: + + virtual bool orientation() {return _orientation;} + virtual void set_edge(value_type iVE) {_ViewEdge=iVE;} + virtual void set_orientation(bool iOrientation) {_orientation = iOrientation;} + virtual void change_orientation() {_orientation = !_orientation;} + + // operators + inline Self& operator++() // operator corresponding to ++i + { + //++_ViewEdge->getTimeStamp(); + increment(); + return *this; + } + inline Self operator++(int) // opérateur correspondant à i++ + { // c.a.d qui renvoie la valeur *puis* incrémente. + //++_ViewEdge->getTimeStamp(); + Self tmp = *this; // C'est pour cela qu'on stocke la valeur + increment(); // dans un temporaire. + return tmp; + } + inline Self& operator--() // operator corresponding to ++i + { + //++_ViewEdge->getTimeStamp(); + decrement(); + return *this; + } + inline Self operator--(int) // opérateur correspondant à i++ + { // c.a.d qui renvoie la valeur *puis* incrémente. + //++_ViewEdge->getTimeStamp(); + Self tmp = *this; // C'est pour cela qu'on stocke la valeur + decrement(); // dans un temporaire. + return tmp; + } + + // comparibility + virtual bool operator!=(const Self& b) const + { + return (_ViewEdge != b._ViewEdge); + } + virtual bool operator==(const Self& b) const + { + return !(*this != b); + } + + // dereferencing + virtual reference operator*() const {return (_ViewEdge);} + virtual pointer operator->() const { return &(operator*());} + + public: + virtual bool begin() const {return _ViewEdge==_first ? true : false;} + virtual bool end() const {return _ViewEdge==0 ? true : false;} + + protected: + virtual void increment() {} + virtual void decrement() {} + }; + + template<class Traits> + class fedge_iterator_base : public IteratorBase<Traits,BidirectionalIteratorTag_Traits> + { + public: + typedef typename Traits::value_type value_type; + typedef typename Traits::difference_type difference_type; + typedef typename Traits::pointer pointer; + typedef typename Traits::reference reference; + typedef fedge_iterator_base<Traits> Self; + public: + typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class; + mutable value_type _FEdge; + value_type _first; + value_type _FEdgeB; // last fedge of the view edge + + public: + friend class ::ViewEdge; + friend class fedge_iterator; + inline fedge_iterator_base() + : parent_class() + {} + inline fedge_iterator_base(const fedge_iterator_base<Nonconst_traits<FEdge*> >& iBrother) + : parent_class() + { + _FEdge = iBrother._FEdge; + _first = iBrother._first; + _FEdgeB = iBrother._FEdgeB; + } + inline fedge_iterator_base(const fedge_iterator_base<Const_traits<FEdge*> >& iBrother) + : parent_class() + { + _FEdge = iBrother._FEdge; + _first = iBrother._first; + _FEdgeB = iBrother._FEdgeB; + } + //protected://FIXME + public: + inline fedge_iterator_base(value_type iEdge, value_type iFEdgeB) + : parent_class() + { + _FEdge = iEdge; + _first = iEdge; + _FEdgeB = iFEdgeB; + } + + public: + virtual ~fedge_iterator_base() {} + // operators + inline Self& operator++() // operator corresponding to ++i + { + increment(); + return *this; + } + inline Self operator++(int) // opérateur correspondant à i++ + { // c.a.d qui renvoie la valeur *puis* incrémente. + Self tmp = *this; // C'est pour cela qu'on stocke la valeur + increment(); // dans un temporaire. + return tmp; + } + inline Self& operator--() // operator corresponding to ++i + { + decrement(); + return *this; + } + inline Self operator--(int) // opérateur correspondant à i++ + { // c.a.d qui renvoie la valeur *puis* incrémente. + Self tmp = *this; // C'est pour cela qu'on stocke la valeur + decrement(); // dans un temporaire. + return tmp; + } + + // comparibility + virtual bool operator!=(const Self& b) const + { + return (_FEdge != b._FEdge); + } + virtual bool operator==(const Self& b) const + { + return !(*this != b); + } + + // dereferencing + virtual reference operator*() const {return (_FEdge);} + virtual pointer operator->() const { return &(operator*());} + + + public: + virtual bool begin() const {return _FEdge==_first ? true : false;} + virtual bool end() const {return _FEdge==0 ? true : false;} + protected: + virtual void increment() + { + _FEdge = _FEdge->nextEdge(); // we don't change or + } + + virtual void decrement() + { + if(0 == _FEdge) + { + _FEdge = _FEdgeB; + return; + } + _FEdge = _FEdge->previousEdge(); // we don't change or + } + }; + + template<class Traits> + class vertex_iterator_base : public IteratorBase<Traits,BidirectionalIteratorTag_Traits> + { + public: + typedef typename Traits::value_type value_type; + typedef typename Traits::difference_type difference_type; + typedef typename Traits::pointer pointer; + typedef typename Traits::reference reference; + typedef vertex_iterator_base<Traits> Self; + protected: + typedef IteratorBase<Traits,BidirectionalIteratorTag_Traits> parent_class; + public: + mutable value_type _SVertex; + FEdge *_NextFEdge; + FEdge *_PreviousFEdge; + public: + friend class ViewEdge; + friend class vertex_iterator; + inline vertex_iterator_base() + : parent_class() + {} + inline vertex_iterator_base(const vertex_iterator_base<Const_traits<SVertex*> >& iBrother) + : parent_class() + { + _SVertex = iBrother._SVertex; + _NextFEdge = iBrother._NextFEdge; + _PreviousFEdge = iBrother._PreviousFEdge; + } + inline vertex_iterator_base(const vertex_iterator_base<Nonconst_traits<SVertex*> >& iBrother) + : parent_class() + { + _SVertex = iBrother._SVertex; + _NextFEdge = iBrother._NextFEdge; + _PreviousFEdge = iBrother._PreviousFEdge; + } + + //protected://FIXME + public: + + inline vertex_iterator_base(value_type iVertex, FEdge *iPreviousFEdge, FEdge *iNextFEdge) + : parent_class() + { + _SVertex = iVertex; + _NextFEdge = iNextFEdge; + _PreviousFEdge = iPreviousFEdge; + } + + public: + virtual ~vertex_iterator_base() {} + + virtual bool begin() const {return _PreviousFEdge==0? true : false;} + virtual bool end() const {return _SVertex==0 ? true : false;} + + // operators + inline Self& operator++() // operator corresponding to ++i + { + increment(); + return *this; + } + inline Self operator++(int) // opérateur correspondant à i++ + { // c.a.d qui renvoie la valeur *puis* incrémente. + Self tmp = *this; // C'est pour cela qu'on stocke la valeur + increment(); // dans un temporaire. + return tmp; + } + inline Self& operator--() // operator corresponding to ++i + { + decrement(); + return *this; + } + inline Self operator--(int) // opérateur correspondant à i++ + { // c.a.d qui renvoie la valeur *puis* incrémente. + Self tmp = *this; // C'est pour cela qu'on stocke la valeur + decrement(); // dans un temporaire. + return tmp; + } + + // comparibility + virtual bool operator!=(const Self& b) const + { + return (_SVertex != b._SVertex); + } + virtual bool operator==(const Self& b) const + { + return !(*this != b); + } + + // dereferencing + virtual reference operator*() const {return (_SVertex);} + virtual pointer operator->() const { return &(operator*());} + + protected: + virtual void increment() + { + if(0 == _NextFEdge) + { + _SVertex = 0; + return; + } + + _SVertex = _NextFEdge->vertexB(); + _PreviousFEdge = _NextFEdge; + _NextFEdge = _NextFEdge->nextEdge(); + + } + virtual void decrement() + { + // if(0 == _SVertex) + // { + // _SVertex = _PreviousFEdge->vertexB(); + // return; + // } + if(0 == _PreviousFEdge) + { + _SVertex = 0; + return; + } + _SVertex = _PreviousFEdge->vertexA(); + _NextFEdge = _PreviousFEdge; + _PreviousFEdge = _PreviousFEdge->previousEdge(); + } + }; + + +} // end of namespace ViewEdgeInternal + +#endif // VIEWMAPADVANCEDITERATORS_H diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp new file mode 100755 index 00000000000..7e582e7f037 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.cpp @@ -0,0 +1,1064 @@ + +// +// 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 "ViewMapBuilder.h" +#include <algorithm> + +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; + +#if 0 + if((Ta < -epsilon) || (Ta > 1+epsilon) || (Tb < -epsilon) || (Tb > 1+epsilon)) { + printf("ta %.12e\n", ta); + printf("tb %.12e\n", tb); + printf("a1 %e, %e -- b1 %e, %e\n", a1[0], a1[1], b1[0], b1[1]); + printf("a2 %e, %e -- b2 %e, %e\n", a2[0], a2[1], b2[0], b2[1]); + if((Ta < -epsilon) || (Ta > 1+epsilon)) + printf("Ta %.12e\n", Ta); + if((Tb < -epsilon) || (Tb > 1+epsilon)) + printf("Tb %.12e\n", Tb); + printf("A1 %e, %e, %e -- B1 %e, %e, %e\n", A1[0], A1[1], A1[2], B1[0], B1[1], B1[2]); + printf("A2 %e, %e, %e -- B2 %e, %e, %e\n", A2[0], A2[1], A2[2], B2[0], B2[1], B2[2]); + } +#endif + + 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(); + // } +} diff --git a/source/blender/freestyle/intern/view_map/ViewMapBuilder.h b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h new file mode 100755 index 00000000000..12b1266fa12 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMapBuilder.h @@ -0,0 +1,226 @@ +// +// Filename : ViewMapBuilder.h +// Author(s) : Stephane Grabli +// Purpose : Class to build silhouette edges from a +// Winged-Edge structure +// Date of creation : 25/03/2002 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VIEWMAPBUILDER_H +# define VIEWMAPBUILDER_H + +# include "Silhouette.h" +# include <vector> +# include "../system/FreestyleConfig.h" +# include "../geometry/Geom.h" +# include "../scene_graph/NodeGroup.h" +# include "../winged_edge/WXEdge.h" +# include "../geometry/GeomUtils.h" +# include "../geometry/Grid.h" +# include "../system/ProgressBar.h" +# include "../geometry/SweepLine.h" +# include "ViewMap.h" +# include "SilhouetteGeomEngine.h" +# include "../scene_graph/TriangleRep.h" +# include "../winged_edge/WEdge.h" +# include "ViewEdgeXBuilder.h" + + +using namespace Geometry; + +class LIB_VIEW_MAP_EXPORT ViewMapBuilder +{ +private: + + ViewMap * _ViewMap; // result + //SilhouetteGeomEngine _GeomEngine; + ProgressBar *_pProgressBar; + Vec3r _viewpoint; + bool _orthographicProjection; + Grid* _Grid; + ViewEdgeXBuilder *_pViewEdgeBuilder; + bool _EnableQI; + double _epsilon; + + // tmp values: + int _currentId; + int _currentFId; + int _currentSVertexId; + + +public: + + typedef enum { + sweep_line + } intersection_algo; + + typedef enum { + ray_casting, + ray_casting_fast, + ray_casting_very_fast + } visibility_algo; + + inline ViewMapBuilder() + { + _pProgressBar = 0; + _Grid = 0; + _currentId = 1; + _currentFId = 0; + _currentSVertexId = 0; + _pViewEdgeBuilder = new ViewEdgeXBuilder; + _EnableQI = true; + } + + inline ~ViewMapBuilder() + { + if(_pViewEdgeBuilder){ + delete _pViewEdgeBuilder; + _pViewEdgeBuilder = 0; + } + } + + /*! Compute Shapes from a WingedEdge containing a list of WShapes */ + void computeInitialViewEdges(WingedEdge&); + + /*! Compute Cusps */ + void computeCusps(ViewMap *ioViewMap); + /*! Detects cusps (for a single ViewEdge) among SVertices and builds a ViewVertex on top of + * each cusp SVertex + * We use a hysteresis approach to avoid noise. + */ + void DetectCusps(ViewEdge *ioEdge); + + + /*! Sets the current viewpoint */ + inline void setViewpoint(const Vec3r& ivp) {_viewpoint = ivp; SilhouetteGeomEngine::setViewpoint(ivp);} + + /*! Sets the current transformation + * iModelViewMatrix + * The 4x4 model view matrix, in column major order (openGL like). + * iProjection matrix + * The 4x4 projection matrix, in column major order (openGL like). + * iViewport + * The viewport. 4 real array: origin.x, origin.y, width, length + */ + inline void setTransform(const real iModelViewMatrix[4][4], + const real iProjectionMatrix[4][4], + const int iViewport[4], + real iFocalLength, + real iAspect, + real iFovy) { + _orthographicProjection = (iProjectionMatrix[3][3] != 0.0); + SilhouetteGeomEngine::setTransform(iModelViewMatrix, iProjectionMatrix, iViewport, iFocalLength); + } + + inline void setFrustum(real iZnear, real iZfar) { + SilhouetteGeomEngine::setFrustum(iZnear, iZfar); + } + + /*! Builds the scene view map + * returns the list the view map + * it is up to the caller to delete this ViewMap + * iWRoot + * The root group node containing the WEdge structured scene + */ + + ViewMap* BuildViewMap(WingedEdge& we, visibility_algo iAlgo = ray_casting, real epsilon=1e-06) ; + /*! computes the intersection between all 2D + * feature edges of the scene. + * ioViewMap + * The view map. It is modified by the method. + * The list of all features edges of the scene. + * Each time an intersection is found, the 2 intersecting + * edges are splitted (creating 2 new vertices) + * At the end, this list is updated with the adding + * of all new created edges (resulting from splitting). + * iAlgo + * The algo to use for computing the intersections + */ + void ComputeIntersections(ViewMap *ioViewMap, intersection_algo iAlgo = sweep_line, real epsilon=1e-06); + + /*! Computes the 2D scene silhouette edges visibility + * iGrid + * For the Ray Casting algorithm. + */ + void ComputeEdgesVisibility(ViewMap *ioViewMap, visibility_algo iAlgo= ray_casting, Grid* iGrid = 0, real epsilon=1e-6); + + void setGrid(Grid *iGrid) {_Grid = iGrid;} + + /*! accessors */ + + /*! Modifiers */ + inline void setProgressBar(ProgressBar *iProgressBar) {_pProgressBar = iProgressBar;} + inline void setEnableQI(bool iBool) {_EnableQI = iBool;} + +protected: + + /*! Computes intersections on all edges of the scene using a sweep line + * algorithm*/ + void ComputeSweepLineIntersections(ViewMap *ioViewMap, real epsilon = 1e-6); + + /*! Computes the 2D scene silhouette edges visibility + * using a ray casting. On each edge, a ray is cast + * to check its quantitative invisibility. The list + * of occluders are each time stored in the tested edge. + * ioViewMap + * The view map. + * The 2D scene silhouette edges as FEdges. + * These edges have already been splitted at their intersections points. + * Thus, these edges do not intersect anymore. + * The visibility corresponding to each edge of ioScene is set is this + * edge. + */ + void ComputeRayCastingVisibility(ViewMap *ioViewMap, Grid *iGrid, real epsilon=1e-6); + void ComputeFastRayCastingVisibility(ViewMap *ioViewMap, Grid *iGrid, real epsilon=1e-6); + void ComputeVeryFastRayCastingVisibility(ViewMap *ioViewMap, Grid *iGrid, real epsilon=1e-6); + + /*! Compute the visibility for the FEdge fe. + * The occluders are added to fe occluders list. + * fe + * The FEdge + * iGrid + * The grid used to compute the ray casting visibility + * epsilon + * The epsilon used for computation + * oShapeId + * fe is the border (in 2D) between 2 2D spaces. + * if fe is a silhouette, + * One of these 2D spaces is occupied by the shape + * to which fe belongs (on its left) and the other one is either occupied + * by another shape or empty or occupied by the same shape. + * We use this ray csating operation to determine which shape + * lies on fe's right. + * The result is the shape id stored in oShapeId + */ + int ComputeRayCastingVisibility(FEdge *fe, Grid* iGrid, real epsilon, set<ViewShape*>& oOccluders, + Polygon3r** oaPolygon, unsigned timestamp); + // FIXME + void FindOccludee(FEdge *fe, Grid* iGrid, real epsilon, Polygon3r** oaPolygon, unsigned timestamp); + void FindOccludee(FEdge *fe, Grid* iGrid, real epsilon, Polygon3r** oaPolygon, unsigned timestamp, + Vec3r& u, Vec3r& A, Vec3r& origin, Vec3r& edge, vector<WVertex*>& faceVertices); + +}; + +#endif // VIEWMAPBUILDER_H diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.cpp b/source/blender/freestyle/intern/view_map/ViewMapIO.cpp new file mode 100755 index 00000000000..f99a574766b --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMapIO.cpp @@ -0,0 +1,1245 @@ + +// +// 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 "ViewMapIO.h" + +#ifdef IRIX +# define WRITE(n) Internal::write<sizeof((n))>(out, (const char*)(&(n))) +# define READ(n) Internal::read<sizeof((n))>(in, (char*)(&(n))) +#else +# define WRITE(n) out.write((const char*)(&(n)), sizeof((n))) +# define READ(n) in.read((char*)(&(n)), sizeof((n))) +#endif + +#define WRITE_IF_NON_NULL(ptr) if ((ptr) == NULL) { WRITE(ZERO); } else { WRITE((ptr)->userdata); } +#define READ_IF_NON_NULL(ptr, array) READ(tmp); if (tmp == ZERO) { (ptr) = NULL; } else { (ptr) = (array)[tmp]; } + +namespace ViewMapIO { + + namespace Internal { + + ViewMap* g_vm; + + //////////////////// 'load' Functions //////////////////// + + inline + int load(istream& in, Vec3r& v) { + + if (Options::getFlags() & Options::FLOAT_VECTORS) { + float tmp; + READ(tmp); + v[0] = tmp; + READ(tmp); + v[1] = tmp; + READ(tmp); + v[2] = tmp; + } else { + Vec3r::value_type tmp; + READ(tmp); + v[0] = tmp; + READ(tmp); + v[1] = tmp; + READ(tmp); + v[2] = tmp; + } + return 0; + } + + + inline + int load(istream& in, Polygon3r& p) { + + unsigned tmp; + + // Id + READ(tmp); + p.setId(tmp); + + // vertices (List) + vector<Vec3r> tmp_vec; + Vec3r v; + READ(tmp); + for (unsigned i = 0; i < tmp; i++) { + load(in, v); + tmp_vec.push_back(v); + } + p.setVertices(tmp_vec); + + // min & max + // Already computed (in the SetVertices() method) + + return 0; + } + + + inline + int load(istream& in, FrsMaterial& m) { + + float tmp_array[4]; + int i; + + // Diffuse + for (i = 0; i < 4; i++) + READ(tmp_array[i]); + m.setDiffuse(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]); + + // Specular + for (i = 0; i < 4; i++) + READ(tmp_array[i]); + m.setSpecular(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]); + + // Ambient + for (i = 0; i < 4; i++) + READ(tmp_array[i]); + m.setAmbient(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]); + + // Emission + for (i = 0; i < 4; i++) + READ(tmp_array[i]); + m.setEmission(tmp_array[0], tmp_array[1], tmp_array[2], tmp_array[3]); + + // Shininess + READ(tmp_array[0]); + m.setShininess(tmp_array[0]); + + return 0; + } + + + int load(istream& in, ViewShape* vs) { + + if (!vs || !vs->sshape()) + return 1; + + // SShape + + // -> Id + Id::id_type id1, id2; + READ(id1); + READ(id2); + vs->sshape()->setId(Id(id1, id2)); + + // -> Importance + float importance; + READ(importance); + vs->sshape()->setImportance(importance); + + // -> BBox + // Not necessary (only used during view map computatiom) + + unsigned i, size, tmp; + + // -> Material + READ(size); + vector<FrsMaterial> frs_materials; + FrsMaterial m; + for(i=0; i<size; ++i){ + load(in, m); + frs_materials.push_back(m); + } + vs->sshape()->setFrsMaterials(frs_materials); + + + + // -> VerticesList (List) + READ(size); + for (i = 0; i < size; i++) { + SVertex* sv; + READ_IF_NON_NULL(sv, g_vm->SVertices()); + vs->sshape()->AddNewVertex(sv); + } + + // -> Chains (List) + READ(size); + for (i = 0; i < size; i++) { + FEdge* fe; + READ_IF_NON_NULL(fe, g_vm->FEdges()); + vs->sshape()->AddChain(fe); + } + + // -> EdgesList (List) + READ(size); + for (i = 0; i < size; i++) { + FEdge* fe; + READ_IF_NON_NULL(fe, g_vm->FEdges()); + vs->sshape()->AddEdge(fe); + } + + // ViewEdges (List) + READ(size); + for (i = 0; i < size; i++) { + ViewEdge* ve; + READ_IF_NON_NULL(ve, g_vm->ViewEdges()); + vs->AddEdge(ve); + } + + // ViewVertices (List) + READ(size); + for (i = 0; i < size; i++) { + ViewVertex* vv; + READ_IF_NON_NULL(vv, g_vm->ViewVertices()); + vs->AddVertex(vv); + } + + return 0; + } + + + int load(istream& in, FEdge* fe) { + + if (!fe) + return 1; + + bool b; + + FEdgeSmooth *fesmooth = 0; + FEdgeSharp * fesharp = 0; + if(fe->isSmooth()){ + fesmooth = dynamic_cast<FEdgeSmooth*>(fe); + }else{ + fesharp = dynamic_cast<FEdgeSharp*>(fe); + } + + // Id + Id::id_type id1, id2; + READ(id1); + READ(id2); + fe->setId(Id(id1, id2)); + + // Nature + Nature::EdgeNature nature; + READ(nature); + fe->setNature(nature); + + // hasVisibilityPoint + // bool b; + // READ(b); + // fe->setHasVisibilityPoint(b); + + Vec3r v; + unsigned int matindex; + + // VisibilityPointA + // load(in, v); + // fe->setVisibilityPointA(v); + + // VisibilityPointB + // load(in, v); + // fe->setVisibilityPointB(v); + + if(fe->isSmooth()){ + // Normal + load(in, v); + fesmooth->setNormal(v); + + // Material + READ(matindex); + fesmooth->setFrsMaterialIndex(matindex); + }else{ + // aNormal + load(in, v); + fesharp->setNormalA(v); + + // bNormal + load(in, v); + fesharp->setNormalB(v); + + // Materials + READ(matindex); + fesharp->setaFrsMaterialIndex(matindex); + READ(matindex); + fesharp->setbFrsMaterialIndex(matindex); + } + + unsigned tmp; + + // VertexA + SVertex* sva; + READ_IF_NON_NULL(sva, g_vm->SVertices()); + fe->setVertexA(sva); + + // VertexB + SVertex* svb; + READ_IF_NON_NULL(svb, g_vm->SVertices()); + fe->setVertexB(svb); + + // NextEdge + FEdge* nfe; + READ_IF_NON_NULL(nfe, g_vm->FEdges()); + fe->setNextEdge(nfe); + + // PreviousEdge + FEdge* pfe; + READ_IF_NON_NULL(pfe, g_vm->FEdges()); + fe->setPreviousEdge(pfe); + + // ViewEdge + ViewEdge* ve; + READ_IF_NON_NULL(ve, g_vm->ViewEdges()); + fe->setViewEdge(ve); + + // Face + // Not necessary (only used during view map computatiom) + + Polygon3r p; + + // aFace + load(in, p); + fe->setaFace(p); + + // occludeeEmpty + READ(b); + fe->setOccludeeEmpty(b); + + // occludeeIntersection + load(in, v); + fe->setOccludeeIntersection(v); + + return 0; + } + + + int load(istream& in, SVertex* sv) { + + if (!sv) + return 1; + + // Id + Id::id_type id1, id2; + READ(id1); + READ(id2); + sv->setId(Id(id1, id2)); + + Vec3r v; + + // Point3D + load(in, v); + sv->setPoint3D(v); + + // Point2D + load(in, v); + sv->setPoint2D(v); + + unsigned tmp; + + // Shape + ViewShape* vs; + READ_IF_NON_NULL(vs, g_vm->ViewShapes()); + sv->setShape(vs->sshape()); + + // pViewVertex + ViewVertex* vv; + READ_IF_NON_NULL(vv, g_vm->ViewVertices()); + sv->setViewVertex(vv); + + unsigned i, size; + + // Normals (List) + READ(size); + for (i = 0; i < size; i++) { + load(in, v); + sv->AddNormal(v); + } + + // FEdges (List) + READ(size); + FEdge* fe; + for (i = 0; i < size; i++) { + READ_IF_NON_NULL(fe, g_vm->FEdges()); + sv->AddFEdge(fe); + } + + return 0; + } + + + int load(istream& in, ViewEdge* ve) { + + if (!ve) + return 1; + + unsigned tmp; + + // Id + Id::id_type id1, id2; + READ(id1); + READ(id2); + ve->setId(Id(id1, id2)); + + // Nature + Nature::EdgeNature nature; + READ(nature); + ve->setNature(nature); + + // QI + READ(tmp); + ve->setQI(tmp); + + // Shape + ViewShape* vs; + READ_IF_NON_NULL(vs, g_vm->ViewShapes()); + ve->setShape(vs); + + // aShape + ViewShape* avs; + READ_IF_NON_NULL(avs, g_vm->ViewShapes()); + ve->setaShape(avs); + + // FEdgeA + FEdge* fea; + READ_IF_NON_NULL(fea, g_vm->FEdges()); + ve->setFEdgeA(fea); + + // FEdgeB + FEdge* feb; + READ_IF_NON_NULL(feb, g_vm->FEdges()); + ve->setFEdgeB(feb); + + // A + ViewVertex* vva; + READ_IF_NON_NULL(vva, g_vm->ViewVertices()); + ve->setA(vva); + + // B + ViewVertex* vvb; + READ_IF_NON_NULL(vvb, g_vm->ViewVertices()); + ve->setB(vvb); + + // Occluders (List) + if (!(Options::getFlags() & Options::NO_OCCLUDERS)) { + unsigned size; + READ(size); + ViewShape* vso; + for (unsigned i = 0; i < size; i++) { + READ_IF_NON_NULL(vso, g_vm->ViewShapes()); + ve->AddOccluder(vso); + } + } + + return 0; + } + + + int load(istream& in, ViewVertex* vv) { + + if (!vv) + return 1; + + unsigned tmp; + bool b; + + // Nature + Nature::VertexNature nature; + READ(nature); + vv->setNature(nature); + + if (vv->getNature() & Nature::T_VERTEX) { + TVertex* tv = dynamic_cast<TVertex*>(vv); + + // Id + Id::id_type id1, id2; + READ(id1); + READ(id2); + tv->setId(Id(id1, id2)); + + // FrontSVertex + SVertex* fsv; + READ_IF_NON_NULL(fsv, g_vm->SVertices()); + tv->setFrontSVertex(fsv); + + // BackSVertex + SVertex* bsv; + READ_IF_NON_NULL(bsv, g_vm->SVertices()); + tv->setBackSVertex(bsv); + + // FrontEdgeA + ViewEdge* fea; + READ_IF_NON_NULL(fea, g_vm->ViewEdges()); + READ(b); + tv->setFrontEdgeA(fea, b); + + // FrontEdgeB + ViewEdge* feb; + READ_IF_NON_NULL(feb, g_vm->ViewEdges()); + READ(b); + tv->setFrontEdgeB(feb, b); + + // BackEdgeA + ViewEdge* bea; + READ_IF_NON_NULL(bea, g_vm->ViewEdges()); + READ(b); + tv->setBackEdgeA(bea, b); + + // BackEdgeB + ViewEdge* beb; + READ_IF_NON_NULL(beb, g_vm->ViewEdges()); + READ(b); + tv->setBackEdgeB(beb, b); + } + else if (vv->getNature() & Nature::NON_T_VERTEX) { + NonTVertex* ntv = dynamic_cast<NonTVertex*>(vv); + + // SVertex + SVertex* sv; + READ_IF_NON_NULL(sv, g_vm->SVertices()); + ntv->setSVertex(sv); + + // ViewEdges (List) + unsigned size; + READ(size); + ViewEdge* ve; + for (unsigned i = 0; i < size; i++) { + READ_IF_NON_NULL(ve, g_vm->ViewEdges()); + READ(b); + ntv->AddViewEdge(ve, b); + } + } + + return 0; + } + + //////////////////// 'save' Functions //////////////////// + + inline + int save(ostream& out, const Vec3r& v) { + + if (Options::getFlags() & Options::FLOAT_VECTORS) { + float tmp; + + tmp = v[0]; + WRITE(tmp); + tmp = v[1]; + WRITE(tmp); + tmp = v[2]; + WRITE(tmp); + } else { + Vec3r::value_type tmp; + + tmp = v[0]; + WRITE(tmp); + tmp = v[1]; + WRITE(tmp); + tmp = v[2]; + WRITE(tmp); + } + return 0; + } + + + inline + int save(ostream& out, const Polygon3r& p) { + + unsigned tmp; + + // Id + tmp = p.getId(); + WRITE(tmp); + + // vertices (List) + tmp = p.getVertices().size(); + WRITE(tmp); + for (vector<Vec3r>::const_iterator i = p.getVertices().begin(); + i != p.getVertices().end(); i++) { + save(out, *i); + } + + // min & max + // Do not need to be saved + + return 0; + } + + + inline + int save(ostream& out, const FrsMaterial& m) { + + unsigned i; + + // Diffuse + for (i = 0; i < 4; i++) + WRITE(m.diffuse()[i]); + + // Specular + for (i = 0; i < 4; i++) + WRITE(m.specular()[i]); + + // Ambient + for (i = 0; i < 4; i++) + WRITE(m.ambient()[i]); + + // Emission + for (i = 0; i < 4; i++) + WRITE(m.emission()[i]); + + // Shininess + float shininess = m.shininess(); + WRITE(shininess); + + return 0; + } + + + int save(ostream& out, ViewShape* vs) { + + if (!vs || !vs->sshape()) { + cerr << "Warning: null ViewShape" << endl; + return 1; + } + + unsigned tmp; + + // SShape + + // -> Id + Id::id_type id = vs->sshape()->getId().getFirst(); + WRITE(id); + id = vs->sshape()->getId().getSecond(); + WRITE(id); + + // -> Importance + float importance = vs->sshape()->importance(); + WRITE(importance); + + // -> BBox + // Not necessary (only used during view map computatiom) + + // -> Material + unsigned size = vs->sshape()->frs_materials().size(); + WRITE(size); + for(unsigned i=0; i<size; ++i) + save(out, vs->sshape()->frs_material(i)); + + // -> VerticesList (List) + tmp = vs->sshape()->getVertexList().size(); + WRITE(tmp); + for (vector<SVertex*>::const_iterator i1 = vs->sshape()->getVertexList().begin(); + i1 != vs->sshape()->getVertexList().end(); i1++) + WRITE_IF_NON_NULL(*i1); + + // -> Chains (List) + tmp = vs->sshape()->getChains().size(); + WRITE(tmp); + for (vector<FEdge*>::const_iterator i2 = vs->sshape()->getChains().begin(); + i2 != vs->sshape()->getChains().end(); i2++) + WRITE_IF_NON_NULL(*i2); + + // -> EdgesList (List) + tmp = vs->sshape()->getEdgeList().size(); + WRITE(tmp); + for (vector<FEdge*>::const_iterator i3 = vs->sshape()->getEdgeList().begin(); + i3 != vs->sshape()->getEdgeList().end(); i3++) + WRITE_IF_NON_NULL(*i3); + + // ViewEdges (List) + tmp = vs->edges().size(); + WRITE(tmp); + for (vector<ViewEdge*>::const_iterator i4 = vs->edges().begin(); + i4 != vs->edges().end(); i4++) + WRITE_IF_NON_NULL(*i4); + + // ViewVertices (List) + tmp = vs->vertices().size(); + WRITE(tmp); + for (vector<ViewVertex*>::const_iterator i5 = vs->vertices().begin(); + i5 != vs->vertices().end(); i5++) + WRITE_IF_NON_NULL(*i5); + + + return 0; + } + + + int save(ostream& out, FEdge* fe) { + + if (!fe) { + cerr << "Warning: null FEdge" << endl; + return 1; + } + + FEdgeSmooth * fesmooth = dynamic_cast<FEdgeSmooth*>(fe); + FEdgeSharp * fesharp = dynamic_cast<FEdgeSharp*>(fe); + + // Id + Id::id_type id = fe->getId().getFirst(); + WRITE(id); + id = fe->getId().getSecond(); + WRITE(id); + + // Nature + Nature::EdgeNature nature = fe->getNature(); + WRITE(nature); + + bool b; + + // hasVisibilityPoint + // b = fe->hasVisibilityPoint(); + // WRITE(b); + + // VisibilityPointA + // save(out, fe->visibilityPointA()); + // + // // VisibilityPointB + // save(out, fe->visibilityPointB()); + + unsigned index; + if(fe->isSmooth()){ + // normal + save(out, fesmooth->normal()); + // material + index = fesmooth->frs_materialIndex(); + WRITE(index); + }else{ + // aNormal + save(out, fesharp->normalA()); + // bNormal + save(out, fesharp->normalB()); + // aMaterial + index = fesharp->aFrsMaterialIndex(); + WRITE(index); + // bMaterial + index = fesharp->bFrsMaterialIndex(); + WRITE(index); + } + + + // VertexA + WRITE_IF_NON_NULL(fe->vertexA()); + + // VertexB + WRITE_IF_NON_NULL(fe->vertexB()); + + // NextEdge + WRITE_IF_NON_NULL(fe->nextEdge()); + + // PreviousEdge + WRITE_IF_NON_NULL(fe->previousEdge()); + + // ViewEdge + WRITE_IF_NON_NULL(fe->viewedge()); + + // Face + // Not necessary (only used during view map computatiom) + + // aFace + save(out, (Polygon3r&)fe->aFace()); + + // occludeeEmpty + b = fe->getOccludeeEmpty(); + WRITE(b); + + // occludeeIntersection + save(out, fe->getOccludeeIntersection()); + + return 0; + } + + + int save(ostream& out, SVertex* sv) { + + if (!sv) { + cerr << "Warning: null SVertex" << endl; + return 1; + } + + unsigned tmp; + + // Id + Id::id_type id = sv->getId().getFirst(); + WRITE(id); + id = sv->getId().getSecond(); + WRITE(id); + + Vec3r v; + + // Point3D + v = sv->point3D(); + save(out, sv->point3D()); + + // Point2D + v = sv->point2D(); + save(out, v); + + // Shape + WRITE_IF_NON_NULL(sv->shape()); + + // pViewVertex + WRITE_IF_NON_NULL(sv->viewvertex()); + + // Normals (List) + // Note: the 'size()' method of a set doesn't seem to return the + // actual size of the given set, so we have to hack it... + set<Vec3r>::const_iterator i; + for (i = sv->normals().begin(), tmp = 0; + i != sv->normals().end(); + i++, tmp++); + WRITE(tmp); + for (i = sv->normals().begin(); i != sv->normals().end(); i++) + save(out, *i); + + // FEdges (List) + tmp = sv->fedges().size(); + WRITE(tmp); + for (vector<FEdge*>::const_iterator j = sv->fedges_begin(); + j != sv->fedges_end(); j++) + WRITE_IF_NON_NULL(*j); + + return 0; + } + + + int save(ostream& out, ViewEdge* ve) { + + if (!ve) { + cerr << "Warning: null ViewEdge" << endl; + return 1; + } + + unsigned tmp; + + // Id + Id::id_type id = ve->getId().getFirst(); + WRITE(id); + id = ve->getId().getSecond(); + WRITE(id); + + // Nature + Nature::EdgeNature nature = ve->getNature(); + WRITE(nature); + + // QI + unsigned qi = ve->qi(); + WRITE(qi); + + // Shape + WRITE_IF_NON_NULL(ve->shape()); + + // aShape + WRITE_IF_NON_NULL(ve->aShape()); + + // FEdgeA + WRITE_IF_NON_NULL(ve->fedgeA()); + + // FEdgeB + WRITE_IF_NON_NULL(ve->fedgeB()); + + // A + WRITE_IF_NON_NULL(ve->A()); + + // B + WRITE_IF_NON_NULL(ve->B()); + + // Occluders (List) + if (!(Options::getFlags() & Options::NO_OCCLUDERS)) { + tmp = ve->occluders().size(); + WRITE(tmp); + for (vector<ViewShape*>::const_iterator i = ve->occluders().begin(); + i != ve->occluders().end(); i++) + WRITE_IF_NON_NULL((*i)); + } + + return 0; + } + + + int save(ostream& out, ViewVertex* vv) { + + if (!vv) { + cerr << "Warning: null ViewVertex" << endl; + return 1; + } + + // Nature + Nature::VertexNature nature = vv->getNature(); + WRITE(nature); + + if (vv->getNature() & Nature::T_VERTEX) { + TVertex* tv = dynamic_cast<TVertex*>(vv); + + // Id + Id::id_type id = tv->getId().getFirst(); + WRITE(id); + id = tv->getId().getSecond(); + WRITE(id); + + // FrontSVertex + WRITE_IF_NON_NULL(tv->frontSVertex()); + + // BackSVertex + WRITE_IF_NON_NULL(tv->backSVertex()); + + // FrontEdgeA + WRITE_IF_NON_NULL(tv->frontEdgeA().first); + WRITE(tv->frontEdgeA().second); + + // FrontEdgeB + WRITE_IF_NON_NULL(tv->frontEdgeB().first); + WRITE(tv->frontEdgeB().second); + + // BackEdgeA + WRITE_IF_NON_NULL(tv->backEdgeA().first); + WRITE(tv->backEdgeA().second); + + // BackEdgeB + WRITE_IF_NON_NULL(tv->backEdgeB().first); + WRITE(tv->backEdgeB().second); + + } + else if (vv->getNature() & Nature::NON_T_VERTEX) { + NonTVertex* ntv = dynamic_cast<NonTVertex*>(vv); + + // SVertex + WRITE_IF_NON_NULL(ntv->svertex()); + + // ViewEdges (List) + unsigned size = ntv->viewedges().size(); + WRITE(size); + vector<ViewVertex::directedViewEdge>::const_iterator i = ntv->viewedges().begin(); + for ( ; i != ntv->viewedges().end(); i++){ + WRITE_IF_NON_NULL(i->first); + WRITE(i->second); + } + + } else { + cerr << "Warning: unexpected ViewVertex nature" << endl; + return 1; + } + + return 0; + } + + } // End of namespace Internal + + + //////////////////// "Public" 'load' and 'save' functions //////////////////// + +#define SET_PROGRESS(n) if (pb) pb->setProgress((n)) + + int load(istream& in, ViewMap* vm, ProgressBar* pb) { + + if (!vm) + return 1; + + //soc unused - unsigned tmp; + + int err = 0; + + Internal::g_vm = vm; + + // Management of the progress bar (if present) + if (pb) { + pb->reset(); + pb->setLabelText("Loading View Map..."); + pb->setTotalSteps(6); + pb->setProgress(0); + } + + // Read and set the options + unsigned char flags; + READ(flags); + Options::setFlags(flags); + + // Read the size of the five ViewMap's lists (with some extra informations for the ViewVertices) + // and instantiate them (with default costructors) + unsigned vs_s, fe_s, fe_rle1, fe_rle2, sv_s, ve_s, vv_s, vv_rle1, vv_rle2; + READ(vs_s); + READ(fe_s); + + if (fe_s) { + bool b; + READ(b); + for (READ(fe_rle1), fe_rle2 = 0; + fe_rle1 < fe_s+1; + fe_rle2 = fe_rle1, READ(fe_rle1)) { + if (b) { + for (unsigned i = fe_rle2; i < fe_rle1; i++) { + FEdgeSmooth * fes = new FEdgeSmooth; + vm->AddFEdge(fes); + } + b = !b; + } + else if (!b) { + for (unsigned i = fe_rle2; i < fe_rle1; i++) { + FEdgeSharp * fes = new FEdgeSharp; + vm->AddFEdge(fes); + } + b = !b; + } + } + } + + READ(sv_s); + READ(ve_s); + READ(vv_s); + + if (vv_s) { + Nature::VertexNature nature; + READ(nature); + for (READ(vv_rle1), vv_rle2 = 0; + vv_rle1 < vv_s+1; + vv_rle2 = vv_rle1, READ(vv_rle1)) { + if (nature & Nature::T_VERTEX) { + for (unsigned i = vv_rle2; i < vv_rle1; i++) { + TVertex* tv = new TVertex(); + vm->AddViewVertex(tv); + } + nature = Nature::NON_T_VERTEX; + } + else if (nature & Nature::NON_T_VERTEX) { + for (unsigned i = vv_rle2; i < vv_rle1; i++) { + NonTVertex* ntv = new NonTVertex(); + vm->AddViewVertex(ntv); + } + nature = Nature::T_VERTEX; + } + } + } + + for (unsigned i0 = 0; i0 < vs_s; i0++) { + SShape* ss = new SShape(); + ViewShape* vs = new ViewShape(); + vs->setSShape(ss); + ss->setViewShape(vs); + vm->AddViewShape(vs); + } + // for (unsigned i1 = 0; i1 < fe_s; i1++) { + // FEdge* fe = new FEdge(); + // vm->AddFEdge(fe); + // } + for (unsigned i2 = 0; i2 < sv_s; i2++) { + SVertex* sv = new SVertex(); + vm->AddSVertex(sv); + } + for (unsigned i3 = 0; i3 < ve_s; i3++) { + ViewEdge* ve = new ViewEdge(); + vm->AddViewEdge(ve); + } + + + // Read the values for all the objects created above + SET_PROGRESS(1); + for (vector<ViewShape*>::const_iterator i4 = vm->ViewShapes().begin(); + i4 != vm->ViewShapes().end(); i4++) + err += Internal::load(in, *i4); + SET_PROGRESS(2); + for (vector<FEdge*>::const_iterator i5 = vm->FEdges().begin(); + i5 != vm->FEdges().end(); i5++) + err += Internal::load(in, *i5); + SET_PROGRESS(3); + for (vector<SVertex*>::const_iterator i6 = vm->SVertices().begin(); + i6 != vm->SVertices().end(); i6++) + err += Internal::load(in, *i6); + SET_PROGRESS(4); + for (vector<ViewEdge*>::const_iterator i7 = vm->ViewEdges().begin(); + i7 != vm->ViewEdges().end(); i7++) + err += Internal::load(in, *i7); + SET_PROGRESS(5); + for (vector<ViewVertex*>::const_iterator i8 = vm->ViewVertices().begin(); + i8 != vm->ViewVertices().end(); i8++) + err += Internal::load(in, *i8); + SET_PROGRESS(6); + + // Read the shape id to index mapping + unsigned map_s; + READ(map_s); + unsigned id,index; + for(unsigned i4=0;i4<map_s;++i4){ + READ(id); + READ(index); + vm->shapeIdToIndexMap()[id] = index; + } + + return err; + } + + + int save(ostream& out, ViewMap* vm, ProgressBar* pb) { + + if (!vm) + return 1; + + int err = 0; + + // Management of the progress bar (if present) + if (pb) { + pb->reset(); + pb->setLabelText("Saving View Map..."); + pb->setTotalSteps(6); + pb->setProgress(0); + } + + // For every object, initialize its userdata member to its index in the ViewMap list + for (unsigned i0 = 0; i0 < vm->ViewShapes().size(); i0++) { + vm->ViewShapes()[i0]->userdata = (void*)i0; + vm->ViewShapes()[i0]->sshape()->userdata = (void*)i0; + } + for (unsigned i1 = 0; i1 < vm->FEdges().size(); i1++) + vm->FEdges()[i1]->userdata = (void*)i1; + for (unsigned i2 = 0; i2 < vm->SVertices().size(); i2++) + vm->SVertices()[i2]->userdata = (void*)i2; + for (unsigned i3 = 0; i3 < vm->ViewEdges().size(); i3++) + vm->ViewEdges()[i3]->userdata = (void*)i3; + for (unsigned i4 = 0; i4 < vm->ViewVertices().size(); i4++) + vm->ViewVertices()[i4]->userdata = (void*)i4; + + // Write the current options + unsigned char flags = Options::getFlags(); + WRITE(flags); + + // Write the size of the five lists (with some extra informations for the ViewVertices) + unsigned size; + size = vm->ViewShapes().size(); + WRITE(size); + size = vm->FEdges().size(); + WRITE(size); + if (size) { + bool b = vm->FEdges()[0]->isSmooth(); + WRITE(b); + for (unsigned i = 0; i < size; i++) { + while (i < size && (vm->FEdges()[i]->isSmooth() == b)) + i++; + if (i < size) { + WRITE(i); + b = !b; + } + } + WRITE(size); + size++; + WRITE(size); + } + size = vm->SVertices().size(); + WRITE(size); + size = vm->ViewEdges().size(); + WRITE(size); + size = vm->ViewVertices().size(); + WRITE(size); + if (size) { + Nature::VertexNature nature = vm->ViewVertices()[0]->getNature(); + WRITE(nature); + nature &= ~Nature::VIEW_VERTEX; + for (unsigned i = 0; i < size; i++) { + while (i < size && (vm->ViewVertices()[i]->getNature() & nature)) + i++; + if (i < size) { + WRITE(i); + nature = vm->ViewVertices()[i]->getNature() & ~Nature::VIEW_VERTEX; + } + } + WRITE(size); + size++; + WRITE(size); + } + + + // Write all the elts of the ViewShapes List + SET_PROGRESS(1); + for (vector<ViewShape*>::const_iterator i5 = vm->ViewShapes().begin(); + i5 != vm->ViewShapes().end(); i5++) + err += Internal::save(out, *i5); + SET_PROGRESS(2); + for (vector<FEdge*>::const_iterator i6 = vm->FEdges().begin(); + i6 != vm->FEdges().end(); i6++) + err += Internal::save(out, *i6); + SET_PROGRESS(3); + for (vector<SVertex*>::const_iterator i7 = vm->SVertices().begin(); + i7 != vm->SVertices().end(); i7++) + err += Internal::save(out, *i7); + SET_PROGRESS(4); + for (vector<ViewEdge*>::const_iterator i8 = vm->ViewEdges().begin(); + i8 != vm->ViewEdges().end(); i8++) + err += Internal::save(out, *i8); + SET_PROGRESS(5); + for (vector<ViewVertex*>::const_iterator i9 = vm->ViewVertices().begin(); + i9 != vm->ViewVertices().end(); i9++) + err += Internal::save(out, *i9); + + // Write the shape id to index mapping + size = vm->shapeIdToIndexMap().size(); + WRITE(size); + unsigned id,index; + for(ViewMap::id_to_index_map::iterator mit=vm->shapeIdToIndexMap().begin(), mitend=vm->shapeIdToIndexMap().end(); mit!=mitend; ++mit){ + id = mit->first; + index = mit->second; + WRITE(id); + WRITE(index); + } + + // Reset 'userdata' members + for (vector<ViewShape*>::const_iterator j0 = vm->ViewShapes().begin(); + j0 != vm->ViewShapes().end(); j0++) { + (*j0)->userdata = 0; + (*j0)->sshape()->userdata = 0; + } + for (vector<FEdge*>::const_iterator j1 = vm->FEdges().begin(); + j1 != vm->FEdges().end(); j1++) + (*j1)->userdata = 0; + for (vector<SVertex*>::const_iterator j2 = vm->SVertices().begin(); + j2 != vm->SVertices().end(); j2++) + (*j2)->userdata = 0; + for (vector<ViewEdge*>::const_iterator j3 = vm->ViewEdges().begin(); + j3 != vm->ViewEdges().end(); j3++) + (*j3)->userdata = 0; + for (vector<ViewVertex*>::const_iterator j4 = vm->ViewVertices().begin(); + j4 != vm->ViewVertices().end(); j4++) + (*j4)->userdata = 0; + SET_PROGRESS(6); + + return err; + } + + + //////////////////// Options //////////////////// + + namespace Options { + + namespace Internal { + + static unsigned char g_flags = 0; + static string g_models_path; + + } // End of namespace Internal + + void setFlags(const unsigned char flags) { + Internal::g_flags = flags; + } + + void addFlags(const unsigned char flags) { + Internal::g_flags |= flags; + } + + void rmFlags(const unsigned char flags) { + Internal::g_flags &= ~flags; + } + + unsigned char getFlags() { + return Internal::g_flags; + } + + void setModelsPath(const string& path) { + Internal::g_models_path = path; + } + + string getModelsPath() { + return Internal::g_models_path; + } + + }; // End of namepace Options + +} // End of namespace ViewMapIO diff --git a/source/blender/freestyle/intern/view_map/ViewMapIO.h b/source/blender/freestyle/intern/view_map/ViewMapIO.h new file mode 100755 index 00000000000..185841a90ec --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMapIO.h @@ -0,0 +1,116 @@ +// +// Filename : ViewMapIO.h +// Author(s) : Emmanuel Turquin +// Purpose : Functions to manage I/O for the view map +// Date of creation : 09/01/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VIEWMAPIO_H +# define VIEWMAPIO_H + +# include "ViewMap.h" +# include <fstream> +# include <string> +# include "../system/FreestyleConfig.h" +# include "../system/ProgressBar.h" + +namespace ViewMapIO { + + static const unsigned ZERO = UINT_MAX; + + LIB_VIEW_MAP_EXPORT + int load(istream& in, ViewMap* vm, ProgressBar* pb = NULL); + + LIB_VIEW_MAP_EXPORT + int save(ostream& out, ViewMap* vm, ProgressBar* pb = NULL); + + namespace Options { + + static const unsigned char FLOAT_VECTORS = 1; + static const unsigned char NO_OCCLUDERS = 2; + + LIB_VIEW_MAP_EXPORT + void setFlags(const unsigned char flags); + + LIB_VIEW_MAP_EXPORT + void addFlags(const unsigned char flags); + + LIB_VIEW_MAP_EXPORT + void rmFlags(const unsigned char flags); + + LIB_VIEW_MAP_EXPORT + unsigned char getFlags(); + + LIB_VIEW_MAP_EXPORT + void setModelsPath(const string& path); + + LIB_VIEW_MAP_EXPORT + string getModelsPath(); + + }; // End of namepace Options + +# ifdef IRIX + + namespace Internal { + + template <unsigned S> + ostream& write(ostream& out, const char* str) { + out.put(str[S - 1]); + return write<S - 1>(out, str); + } + + template<> + ostream& write<1>(ostream& out, const char* str) { + return out.put(str[0]); + } + + template<> + ostream& write<0>(ostream& out, const char*) { + return out; + } + + template <unsigned S> + istream& read(istream& in, char* str) { + in.get(str[S - 1]); + return read<S - 1>(in, str); + } + + template<> + istream& read<1>(istream& in, char* str) { + return in.get(str[0]); + } + + template<> + istream& read<0>(istream& in, char*) { + return in; + } + + } // End of namespace Internal + +# endif // IRIX + +} // End of namespace ViewMapIO + +#endif // VIEWMAPIO_H diff --git a/source/blender/freestyle/intern/view_map/ViewMapIterators.h b/source/blender/freestyle/intern/view_map/ViewMapIterators.h new file mode 100755 index 00000000000..789aec0d5c3 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMapIterators.h @@ -0,0 +1,549 @@ +// +// Filename : ViewMapIterators.h +// Author(s) : Stephane Grabli +// Purpose : Iterators used to iterate over the various elements +// of the ViewMap +// Date of creation : 01/07/2003 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VIEWMAPITERATORS_H +# define VIEWMAPITERATORS_H + +#include "ViewMap.h" +#include "../system/Iterator.h" //soc + + + /**********************************/ + /* */ + /* */ + /* ViewMap */ + /* */ + /* */ + /**********************************/ + + /**********************************/ + /* */ + /* */ + /* ViewVertex */ + /* */ + /* */ + /**********************************/ + +namespace ViewVertexInternal{ + + /*! Class representing an iterator over oriented ViewEdges + * around a ViewVertex. This iterator allows a CCW iteration + * (in the image plane). + * An instance of an orientedViewEdgeIterator can only + * be obtained from a ViewVertex by calling edgesBegin() or edgesEnd(). + */ + class orientedViewEdgeIterator : public Iterator + { + public: + friend class ViewVertex; + friend class TVertex; + friend class NonTVertex; + friend class ViewEdge; + + // FIXME + typedef ::TVertex::edge_pointers_container edge_pointers_container; + typedef ::NonTVertex::edges_container edges_container; + protected: + + Nature::VertexNature _Nature; // the nature of the underlying vertex + // T vertex attributes + edge_pointers_container::iterator _tbegin; + edge_pointers_container::iterator _tend; + edge_pointers_container::iterator _tvertex_iter; + + // Non TVertex attributes + edges_container::iterator _begin; + edges_container::iterator _end; + edges_container::iterator _nontvertex_iter; + + public: + /*! Default constructor */ + inline orientedViewEdgeIterator() {} + inline orientedViewEdgeIterator(Nature::VertexNature iNature) + {_Nature = iNature;} + /*! Copy constructor */ + orientedViewEdgeIterator(const orientedViewEdgeIterator& iBrother) + { + _Nature = iBrother._Nature; + if(_Nature & Nature::T_VERTEX) + { + _tbegin = iBrother._tbegin; + _tend = iBrother._tend; + _tvertex_iter = iBrother._tvertex_iter; + } + else + { + _begin = iBrother._begin; + _end = iBrother._end; + _nontvertex_iter = iBrother._nontvertex_iter; + } + } + virtual ~orientedViewEdgeIterator() {} + + public: + inline orientedViewEdgeIterator(edge_pointers_container::iterator begin, + edge_pointers_container::iterator end, + edge_pointers_container::iterator iter) + { + _Nature = Nature::T_VERTEX; + _tbegin = begin; + _tend = end; + _tvertex_iter = iter; + } + inline orientedViewEdgeIterator(edges_container::iterator begin, + edges_container::iterator end, + edges_container::iterator iter) + { + _Nature = Nature::NON_T_VERTEX; + _begin = begin; + _end = end; + _nontvertex_iter = iter; + } + + public: + + + /*! Tells whether the ViewEdge pointed + * by this iterator is the first one of the + * iteration list or not. + */ + virtual bool isBegin() const + { + if(_Nature & Nature::T_VERTEX) + return (_tvertex_iter == _tbegin); + else + return (_nontvertex_iter == _begin); + } + /*! Tells whether the ViewEdge pointed + * by this iterator is after the last one of the + * iteration list or not. + */ + virtual bool isEnd() const + { + if(_Nature & Nature::T_VERTEX) + return (_tvertex_iter == _tend); + else + return (_nontvertex_iter == _end); + } + + // operators + /*! Increments.In the scripting language, call + * "increment()". + */ + virtual orientedViewEdgeIterator& operator++() // operator corresponding to ++i + { + increment(); + return *this; + } + /*! Increments.In the scripting language, call + * "increment()". + */ + virtual orientedViewEdgeIterator operator++(int) // opérateur correspondant à i++ + { // c.a.d qui renvoie la valeur *puis* incrémente. + orientedViewEdgeIterator tmp = *this; // C'est pour cela qu'on stocke la valeur + increment(); // dans un temporaire. + return tmp; + } + + // comparibility + /*! operator != */ + virtual bool operator!=(const orientedViewEdgeIterator& b) const + { + if(_Nature & Nature::T_VERTEX) + return (_tvertex_iter != b._tvertex_iter); + else + return (_nontvertex_iter != b._nontvertex_iter); + } + + /*! operator == */ + virtual bool operator==(const orientedViewEdgeIterator& b) const + {return !(*this != b);} + + // dereferencing + /*! Returns a reference to the pointed orientedViewEdge. + * In the scripting language, you must call + * "getObject()"instead. + */ + virtual ::ViewVertex::directedViewEdge& operator*() const + { + if(_Nature & Nature::T_VERTEX) + //return _tvertex_iter; + return **_tvertex_iter; + else + return (*_nontvertex_iter); + } + /*! Returns a pointer to the pointed orientedViewEdge. + * Can't be called in the scripting language. + */ + virtual ::ViewVertex::directedViewEdge* operator->() const { return &(operator*());} + + public: + /*! increments.*/ + virtual inline int increment() + { + if(_Nature & Nature::T_VERTEX) + { + ::ViewVertex::directedViewEdge tmp = (**_tvertex_iter); + ++_tvertex_iter; + if(_tvertex_iter != _tend){ + // FIXME : pquoi deja ? + ::ViewVertex::directedViewEdge tmp2 = (**_tvertex_iter); + if(tmp2.first == tmp.first) + ++_tvertex_iter; + } + } + else + ++_nontvertex_iter; + return 0; + } + }; + + } + /**********************************/ + /* */ + /* */ + /* ViewEdge */ + /* */ + /* */ + /**********************************/ + +namespace ViewEdgeInternal { +// +// SVertexIterator +// +///////////////////////////////////////////////// + + class SVertexIterator : public Interface0DIteratorNested + { + public: + + SVertexIterator() { + _vertex = NULL; + _begin = NULL; + _previous_edge = NULL; + _next_edge = NULL; + _t = 0; + } + + SVertexIterator(const SVertexIterator& vi) { + _vertex = vi._vertex; + _begin = vi._begin; + _previous_edge = vi._previous_edge; + _next_edge = vi._next_edge; + _t = vi._t; + } + + SVertexIterator(SVertex* v, SVertex* begin, FEdge* prev, FEdge* next, float t) { + _vertex = v; + _begin = begin; + _previous_edge = prev; + _next_edge = next; + _t = t; + } + + SVertexIterator& operator=(const SVertexIterator& vi) { + _vertex = vi._vertex; + _begin = vi._begin; + _previous_edge = vi._previous_edge; + _next_edge = vi._next_edge; + _t = vi._t; + return *this; + } + + virtual ~SVertexIterator() {} + + virtual string getExactTypeName() const { + return "SVertexIterator"; + } + + virtual SVertex& operator*() { + return *_vertex; + } + + virtual SVertex* operator->() { + return &(operator*()); + } + + virtual SVertexIterator& operator++() { + increment(); + return *this; + } + + virtual SVertexIterator operator++(int) { + SVertexIterator ret(*this); + increment(); + return ret; + } + + virtual SVertexIterator& operator--() { + decrement(); + return *this; + } + + virtual SVertexIterator operator--(int) { + SVertexIterator ret(*this); + decrement(); + return ret; + } + + virtual int increment(){ + if (!_next_edge) { + _vertex = 0; + return 0; + } + _t += (float)_next_edge->getLength2D(); + _vertex = _next_edge->vertexB(); + _previous_edge = _next_edge; + _next_edge = _next_edge->nextEdge(); + return 0; + + } + virtual int decrement(){ + if (!_previous_edge) { + _vertex = 0; + return 0; + } + if((!_next_edge) && (!_vertex)){ + _vertex = _previous_edge->vertexB(); + return 0; + } + _t -= (float)_previous_edge->getLength2D(); + _vertex = _previous_edge->vertexA(); + _next_edge = _previous_edge; + _previous_edge = _previous_edge->previousEdge(); + return 0; + } + + virtual bool isBegin() const { + return _vertex == _begin; + } + + virtual bool isEnd() const { + return (!_vertex) || (_vertex == _begin && _previous_edge); + } + + virtual float t() const { + return _t; + } + virtual float u() const { + return _t/(float)_next_edge->viewedge()->getLength2D(); + } + + virtual bool operator==(const Interface0DIteratorNested& it) const { + const SVertexIterator* it_exact = dynamic_cast<const SVertexIterator*>(&it); + if (!it_exact) + return false; + return (_vertex == it_exact->_vertex); + } + + virtual SVertexIterator* copy() const { + return new SVertexIterator(*this); + } + + private: + + SVertex* _vertex; + SVertex* _begin; + FEdge* _previous_edge; + FEdge* _next_edge; + float _t; // curvilinear abscissa + }; + + + +// +// ViewEdgeIterator (base class) +// +/////////////////////////////////////////////////////////// + + /*! Base class for iterators over ViewEdges of the ViewMap Graph. + * Basically the "increment()" operator of this class should + * be able to take the decision of "where" (on which ViewEdge) to go + * when pointing on a given ViewEdge. + * ::Caution::: the dereferencing operator returns a *pointer* to + * the pointed ViewEdge. + */ +class ViewEdgeIterator : public Iterator +{ +public: + + /*! Builds a ViewEdgeIterator from a starting ViewEdge and its orientation. + * \param begin + * The ViewEdge from where to start the iteration. + * \param orientation + * If true, we'll look for the next ViewEdge among the + * ViewEdges that surround the ending ViewVertex of begin. + * If false, we'll search over the ViewEdges surrounding + * the ending ViewVertex of begin. + */ + ViewEdgeIterator(ViewEdge* begin = 0, bool orientation = true) { + _orientation = orientation; + _edge = begin; + _begin = begin; + } + + /*! Copy constructor */ + ViewEdgeIterator(const ViewEdgeIterator& it) { + _orientation = it._orientation; + _edge = it._edge; + _begin = it._begin; + } + + virtual ~ViewEdgeIterator() {} + + /*! Returns the string "ViewEdgeIterator" */ + virtual string getExactTypeName() const { + return "ViewEdgeIterator"; + } + + /*! Returns the current pointed ViewEdge. */ + ViewEdge* getCurrentEdge() { + return _edge; + } + + /*! Sets the current pointed ViewEdge. */ + void setCurrentEdge(ViewEdge* edge) { + _edge = edge; + } + + /*! Returns the first ViewEdge used for the iteration. */ + ViewEdge* getBegin() { + return _begin; + } + + /*! Sets the first ViewEdge used for the iteration. */ + void setBegin(ViewEdge* begin) { + _begin = begin; + } + + /*! Gets the orientation of the pointed ViewEdge in the iteration. */ + bool getOrientation() const { + return _orientation; + } + + /*! Sets the orientation of the pointed ViewEdge in the iteration. */ + void setOrientation(bool orientation) { + _orientation = orientation; + } + + /*! Changes the current orientation. */ + void changeOrientation() { + _orientation = !_orientation; + } + + /*! Returns a *pointer* to the pointed ViewEdge. */ + virtual ViewEdge* operator*() { + return _edge; + } + + virtual ViewEdge* operator->() { + return operator*(); + } + + /*! Increments. In the scripting language, call + * "increment()". + */ + virtual ViewEdgeIterator& operator++() { + increment(); + return *this; + } + + /*! Increments. In the scripting language, call + * "increment()". + */ + virtual ViewEdgeIterator operator++(int) { + ViewEdgeIterator tmp(*this); + increment(); + return tmp; + } + + /*! increments. */ + virtual int increment() { + cerr << "Warning: method increment() not implemented" << endl; + return 0; + } + + /*! Decrements. In the scripting language, call + * "decrement()". + */ + virtual ViewEdgeIterator& operator--() { + decrement(); + return *this; + } + + /*! Decrements. In the scripting language, call + * "decrement()". + */ + virtual ViewEdgeIterator operator--(int) { + ViewEdgeIterator tmp(*this); + decrement(); + return tmp; + } + + /*! decrements. */ + virtual int decrement(){ + cerr << "Warning: method decrement() not implemented" << endl; + return 0; + } + + /*! Returns true if the pointed ViewEdge is the + * first one used for the iteration. + */ + virtual bool isBegin() const { + return _edge == _begin; + } + + /*! Returns true if the pointed ViewEdge* equals 0. + */ + virtual bool isEnd() const { + return !_edge; + } + + /*! operator == */ + virtual bool operator==(ViewEdgeIterator& it) const { + return _edge == it._edge; + } + + /*! operator != */ + virtual bool operator!=(ViewEdgeIterator& it) const { + return !(*this == it); + } + +protected: + + bool _orientation; + ViewEdge* _edge; + ViewEdge* _begin; +}; + +} // end of namespace ViewEdgeInternal + +#endif // VIEWMAPITERATORS_H + diff --git a/source/blender/freestyle/intern/view_map/ViewMapTesselator.cpp b/source/blender/freestyle/intern/view_map/ViewMapTesselator.cpp new file mode 100755 index 00000000000..6041f527d17 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMapTesselator.cpp @@ -0,0 +1,36 @@ + +// +// 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 "ViewMapTesselator.h" + +NodeGroup* ViewMapTesselator::Tesselate(ViewMap *iViewMap) +{ + if(0 == iViewMap->ViewEdges().size()) + return NULL; + + const vector<ViewEdge*>& viewedges = iViewMap->ViewEdges(); + return Tesselate(viewedges.begin(), viewedges.end()); +} + +NodeGroup* ViewMapTesselator::Tesselate(WShape *) +{ + return NULL; +} diff --git a/source/blender/freestyle/intern/view_map/ViewMapTesselator.h b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h new file mode 100755 index 00000000000..0177dc630b8 --- /dev/null +++ b/source/blender/freestyle/intern/view_map/ViewMapTesselator.h @@ -0,0 +1,196 @@ +// +// Filename : ViewMapTesselator.h +// Author(s) : Stephane Grabli +// Purpose : Class to build a Node Tree designed to be displayed +// from a Silhouette View Map structure. +// Date of creation : 26/03/2002 +// +/////////////////////////////////////////////////////////////////////////////// + + +// +// 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. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifndef VIEWMAPTESSELATOR_H +# define VIEWMAPTESSELATOR_H + +# include "Silhouette.h" +# include "ViewMap.h" +# include "../scene_graph/NodeShape.h" +# include "../winged_edge/WEdge.h" +# include "../scene_graph/NodeGroup.h" +# include "../scene_graph/LineRep.h" +# include "../scene_graph/OrientedLineRep.h" +# include "../scene_graph/VertexRep.h" + +class NodeShape; +class NodeGroup; +class SShape; +class WShape; + +class LIB_VIEW_MAP_EXPORT ViewMapTesselator +{ +public: + + inline ViewMapTesselator() {_nature = Nature::SILHOUETTE | Nature::BORDER | Nature::CREASE;_FrsMaterial.setDiffuse(0,0,0,1);_overloadFrsMaterial=false;} + virtual ~ViewMapTesselator() {} + + /*! Builds a set of lines rep contained under a + * a NodeShape, itself contained under a NodeGroup from a ViewMap + */ + NodeGroup* Tesselate(ViewMap* iViewMap) ; + + /*! Builds a set of lines rep contained under a + * a NodeShape, itself contained under a NodeGroup from a + * set of view edges + */ + template<class ViewEdgesIterator> + NodeGroup* Tesselate(ViewEdgesIterator begin, ViewEdgesIterator end) ; + + /*! Builds a set of lines rep contained among a + * a NodeShape, from a WShape + */ + NodeGroup* Tesselate(WShape* iWShape); + + + inline void setNature(Nature::EdgeNature iNature) {_nature = iNature;} + inline void setFrsMaterial(const FrsMaterial& iMaterial) {_FrsMaterial=iMaterial;_overloadFrsMaterial=true;} + inline Nature::EdgeNature nature() {return _nature;} + inline const FrsMaterial& frs_material() const {return _FrsMaterial;} + +protected: + virtual void AddVertexToLine(LineRep *iLine, SVertex *v) = 0; + +private: + Nature::EdgeNature _nature; + FrsMaterial _FrsMaterial; + bool _overloadFrsMaterial; +}; + +/*! Class to tesselate the 2D projected silhouette */ +class ViewMapTesselator2D : public ViewMapTesselator +{ +public: + inline ViewMapTesselator2D() : ViewMapTesselator() {} + virtual ~ViewMapTesselator2D() {} + +protected: + virtual void AddVertexToLine(LineRep *iLine, SVertex *v) + { + iLine->AddVertex(v->point2D()); + } +}; + +/*! Class to tesselate the 3D silhouette */ +class ViewMapTesselator3D : public ViewMapTesselator +{ +public: + inline ViewMapTesselator3D() : ViewMapTesselator() {} + virtual ~ViewMapTesselator3D() {} + +protected: + virtual void AddVertexToLine(LineRep *iLine, SVertex *v) + { + iLine->AddVertex(v->point3D()); + } +}; + +// +// Implementation +// +/////////////////////////////////////////////// + +template<class ViewEdgesIterator> +NodeGroup * ViewMapTesselator::Tesselate(ViewEdgesIterator begin, ViewEdgesIterator end) +{ + NodeGroup *group = new NodeGroup; + NodeShape *tshape = new NodeShape; + group->AddChild(tshape); + //tshape->frs_material().setDiffuse(0.f, 0.f, 0.f, 1.f); + tshape->setFrsMaterial(_FrsMaterial); + + LineRep* line; + + + FEdge *firstEdge; + FEdge *nextFEdge, *currentEdge; + + int id=0; + // for(vector<ViewEdge*>::const_iterator c=viewedges.begin(),cend=viewedges.end(); + // c!=cend; + // c++) + for(ViewEdgesIterator c=begin, cend=end; + c!=cend; + c++) + { + // if((*c)->qi() > 0){ + // continue; + // } + // if(!((*c)->nature() & (_nature))) + // continue; + // + firstEdge = (*c)->fedgeA(); + + // if(firstEdge->invisibility() > 0) + // continue; + + line = new OrientedLineRep(); + if(_overloadFrsMaterial) + line->setFrsMaterial(_FrsMaterial); + + // there might be chains containing a single element + if(0 == (firstEdge)->nextEdge()) + { + line->setStyle(LineRep::LINES); + // line->AddVertex((*c)->vertexA()->point3D()); + // line->AddVertex((*c)->vertexB()->point3D()); + AddVertexToLine(line, firstEdge->vertexA()); + AddVertexToLine(line, firstEdge->vertexB()); + } + else + { + line->setStyle(LineRep::LINE_STRIP); + + //firstEdge = (*c); + nextFEdge = firstEdge; + currentEdge = firstEdge; + do + { + //line->AddVertex(nextFEdge->vertexA()->point3D()); + AddVertexToLine(line, nextFEdge->vertexA()); + currentEdge = nextFEdge; + nextFEdge = nextFEdge->nextEdge(); + }while((nextFEdge != NULL) && (nextFEdge != firstEdge)); + // Add the last vertex + //line->AddVertex(currentEdge->vertexB()->point3D()); + AddVertexToLine(line, currentEdge->vertexB()); + + } + + line->setId((*c)->getId().getFirst()); + line->ComputeBBox(); + tshape->AddRep(line); + id++; + } + + return group; +} + +#endif // VIEWMAPTESSELATOR_H |