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); }
void FEdgeXDetector::ProcessSilhouetteEdge(WXEdge *iEdge, bool meshSilhouettes) { if(iEdge->nature() & Nature::BORDER) return; // SILHOUETTE ? //------------- WXFace * fA = (WXFace *)iEdge->GetaOEdge()->GetaFace(); WXFace * fB = (WXFace *)iEdge->GetaOEdge()->GetbFace(); if((fA->front(_useConsistency))^(fB->front(_useConsistency))){ // fA->visible XOR fB->visible (true if one is 0 and the other is 1) // Freestyle is using a hack here to determine if these faces are "smooth" or "sharp." Specifically, // if the normals disagree at a vertex, then it must be "sharp." This hack broke with the bunny triangle mesh that had planar // faces in one version. New hack includes more tests... if(!meshSilhouettes && fA->GetVertexNormal(iEdge->GetaVertex()) == fB->GetVertexNormal(iEdge->GetaVertex()) && fA->GetVertexNormal(iEdge->GetbVertex()) == fB->GetVertexNormal(iEdge->GetbVertex()) && fA->GetVertexNormal(iEdge->GetaVertex()) != fA->GetVertexNormal(iEdge->GetbVertex())) // Aaron: added second and third conditions { // Vec3r Aa = fA->GetVertexNormal(iEdge->GetaVertex()); // Vec3r Ba = fB->GetVertexNormal(iEdge->GetaVertex()); // Vec3r Ab = fA->GetVertexNormal(iEdge->GetbVertex()); // Vec3r Bb = fB->GetVertexNormal(iEdge->GetbVertex()); // printf("Non-silhouette detected\n"); // printf("%f %f %f, %f %f %f\n", Aa[0], Aa[1], Aa[2], Ba[0], Ba[1], Ba[2]); // printf("%f %f %f, %f %f %f\n", Ab[0], Ab[1], Ab[2], Bb[0], Bb[1], Bb[2]); return; } iEdge->AddNature(Nature::SILHOUETTE); if(fB->front(_useConsistency)) iEdge->SetOrder(1); else iEdge->SetOrder(-1); } }
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); } }
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(); }
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); //printf("\n\nmesh silhouette = %d\n\n",wxs->MeshSilhouettes()); 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); // skipping crease detection: // 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(); } }
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 }
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; */ /* UNUSED */ // 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 =*/ /* UNUSED */ 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()); }
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); }