void FEdgeXDetector::ProcessSilhouetteFace(WXFace *iFace, bool meshSilhouettes) { real NdotVepsilonHack = 0;// 0.05; //0.1; //0.01; //0.1; // SILHOUETTE LAYER // 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); Vec3r normal; if(meshSilhouettes){ // Use per face normal normal = (iFace->GetVertex(2)->GetVertex() - iFace->GetVertex(0)->GetVertex()) ^ (iFace->GetVertex(1)->GetVertex() - iFace->GetVertex(0)->GetVertex()); normal.normalize(); } for(int i=0; i<numVertices; i++){ point = iFace->GetVertex(i)->GetVertex(); if(!meshSilhouettes){ // Use per vertex normal normal = iFace->GetVertexNormal(i); normal.normalize(); } Vec3r V(_Viewpoint - point); V.normalize(); real d = normal * V + NdotVepsilonHack; faceLayer->PushDotP(d); // Find the point the closest to the viewpoint Vec3r dist_vec(point - _Viewpoint); dist = dist_vec.norm(); if(dist < minDist) { minDist = dist; closestPointId = i; } // store ndotv at the vertex for use in the region-based visibility // assert(dynamic_cast<WXVertex*>(iFace->GetVertex(i))!=NULL); ((WXVertex*)iFace->GetVertex(i))->setNdotV(d); } // Set the closest point id: faceLayer->SetClosestPointIndex(closestPointId); // Add this layer to the face: iFace->AddSmoothLayer(faceLayer); }
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); } #if 0 // 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); } } #endif }
// 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); } #if 0 // XXX fabs(flayer->dotP(i)) < threshold cannot be true 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); } } #endif }
void FEdgeXDetector::ProcessSilhouetteFace(WXFace *iFace) { // SILHOUETTE LAYER Vec3f normal; // Compute the dot products between View direction and N at each vertex of the face: Vec3f point; int closestPointId = 0; float 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(); Vec3f V; if (_orthographicProjection) { V = Vec3f(0.0f, 0.0f, _Viewpoint.z() - point.z()); } else { V = Vec3f(_Viewpoint - point); } V.normalize(); float d = normal * V; faceLayer->PushDotP(d); // Find the point the closest to the viewpoint if (_orthographicProjection) { dist = point.z() - _Viewpoint.z(); } else { Vec3f 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::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.0e-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 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)); #if 0 // 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); } #endif }
OWXFaceLayer ViewEdgeXBuilder::FindPreviousFaceLayer(const OWXFaceLayer& iFaceLayer) { WXFace *previousFace = NULL; 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(NULL, true); bool found = false; WVertex::face_iterator f = previousVertex->faces_begin(); WVertex::face_iterator fend = previousVertex->faces_end(); for (; (!found) && (f != fend); ++f) { previousFace = dynamic_cast<WXFace*>(*f); if ((0 != previousFace) && (previousFace != iFaceLayer.fl->getFace())) { vector<WXFaceLayer*> sameNatureLayers; previousFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers); // don't know... Maybe should test whether this face has also a vertex_edge configuration if (sameNatureLayers.size() == 1) { WXFaceLayer *winner = sameNatureLayers[0]; // check face mark continuity if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark()) return OWXFaceLayer(NULL, true); if (woebegin == winner->getSmoothEdge()->woeb()->twin()) return OWXFaceLayer(winner, true); else return OWXFaceLayer(winner, false); } } } } else { previousFace = dynamic_cast<WXFace*>(iFaceLayer.fl->getFace()->GetBordingFace(woebegin)); if (0 == previousFace) return OWXFaceLayer(NULL, 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(NULL, true); vector<WXFaceLayer*> sameNatureLayers; previousFace->retrieveSmoothEdgesLayers(iFaceLayer.fl->nature(), sameNatureLayers); // don't know how to deal with several edges of same nature on a single face if ((sameNatureLayers.empty()) || (sameNatureLayers.size() != 1)) { return OWXFaceLayer(NULL, true); } else { WXFaceLayer *winner = sameNatureLayers[0]; // check face mark continuity if (winner->getFace()->GetMark() != iFaceLayer.fl->getFace()->GetMark()) return OWXFaceLayer(NULL, true); if (woebegin == winner->getSmoothEdge()->woeb()->twin()) return OWXFaceLayer(winner, true); else return OWXFaceLayer(winner, false); } } return OWXFaceLayer(NULL, true); }