Beispiel #1
0
/*! gts_vertex_gaussian_curvature:
 *  @v: a #WVertex.
 *  @s: a #GtsSurface.
 *  @Kg: the Discrete Gaussian Curvature approximation at @v.
 *
 *  Computes the Discrete Gaussian Curvature approximation at @v.
 *
 *  This approximation is from the paper:
 *      Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
 *      Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
 *      VisMath '02, Berlin (Germany)
 *      http://www-grail.usc.edu/pubs.html
 *
 *  Returns: %true if the operator could be evaluated, %false if the evaluation failed for some reason (@v is
 * boundary or is the endpoint of a non-manifold edge.)
 */
bool gts_vertex_gaussian_curvature(WVertex *v, real *Kg)
{
	real area = 0.0;
	real angle_sum = 0.0;

	if (!v)
		return false;
	if (!Kg)
		return false;

	/* this operator is not defined for boundary edges */
	if (v->isBoundary()) {
		*Kg = 0.0;
		return false;
	}

	WVertex::incoming_edge_iterator itE;
	for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++) {
		area += (*itE)->GetaFace()->getArea();
	}

	for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++) {
		WOEdge *e = (*itE)->getPrevOnFace();
		WVertex *v1 = e->GetaVertex();
		WVertex *v2 = e->GetbVertex();
		angle_sum += angle_from_cotan(v, v1, v2);
	}

	*Kg = (2.0 * M_PI - angle_sum) / area;

	return true;
}
Beispiel #2
0
bool AdvanceToEdge(WFace * face, Vec3r currentPoint, int edgeIndex, Vec3r & nextPoint)
{
  Vec3r viewpoint = SilhouetteGeomEngine::GetViewpoint();
  
  WOEdge * edge = face->GetOEdge(edgeIndex);

  Vec3r A = edge->GetaVertex()->GetVertex();
  Vec3r B = edge->GetbVertex()->GetVertex();

  Vec3r edgedir = B-A;
  Vec3r planeNormal = (viewpoint - currentPoint) ^ face->GetNormal();
  real t;
  GeomUtils::intersection_test result = GeomUtils::intersectLinePlanePN(A, edgedir, planeNormal, currentPoint, t);

  //  printf("\te = %d, result = %d, want: %d, t = %f\n", edgeIndex, result, GeomUtils::DO_INTERSECT, t);
  if (result != GeomUtils::DO_INTERSECT || t < 0 || t > 1)
    return false;

  nextPoint = A + t*edgedir;

  return true;
  /*
  real dp = (nextPoint - currentPoint) * (viewpoint - currentPoint) ;

  printf("\tdp = %f\n", dp);

  return dp > 0;
  */
}
Beispiel #3
0
static bool angle_obtuse(WVertex *v, WFace *f)
{
	WOEdge *e;
	f->getOppositeEdge(v, e);

	Vec3r vec1(e->GetaVertex()->GetVertex() - v->GetVertex());
	Vec3r vec2(e->GetbVertex()->GetVertex() - v->GetVertex());
	return ((vec1 * vec2) < 0);
}
Beispiel #4
0
WVertex::incoming_edge_iterator WVertex::incoming_edges_end()
{
	WOEdge *begin;
	WOEdge *aOEdge = _EdgeList.front()->GetaOEdge();
	if (aOEdge->GetbVertex() == this)
		begin = aOEdge;
	else
		begin = _EdgeList.front()->GetbOEdge();
	return incoming_edge_iterator(this, begin, 0);
}
Beispiel #5
0
void WVertex::incoming_edge_iterator::increment()
{
	WOEdge *twin = _current->twin();
	if (!twin) {
		// we reached a hole
		_current = 0;
		return;
	}
	WOEdge *next = twin->getPrevOnFace();
	if (next == _begin) {
		next = NULL;
	}
	_current = next;
}
Beispiel #6
0
WOEdge::WOEdge(WOEdge& iBrother)
{
	_paVertex = iBrother.GetaVertex();
	_pbVertex = iBrother.GetbVertex();
	_paFace = iBrother.GetaFace();
	_pbFace = iBrother.GetbFace();
	_pOwner = iBrother.GetOwner();
	userdata = NULL;
	iBrother.userdata = new oedgedata;
	((oedgedata *)(iBrother.userdata))->_copy = this;

	_vec = iBrother._vec;
	_angle = iBrother._angle;
}
Beispiel #7
0
/*! gts_vertex_mean_curvature_normal:
 *  @v: a #WVertex.
 *  @s: a #GtsSurface.
 *  @Kh: the Mean Curvature Normal at @v.
 *
 *  Computes the Discrete Mean Curvature Normal approximation at @v.
 *  The mean curvature at @v is half the magnitude of the vector @Kh.
 *
 *  Note: the normal computed is not unit length, and may point either into or out of the surface, depending on
 *  the curvature at @v. It is the responsibility of the caller of the function to use the mean curvature normal
 *  appropriately.
 *
 *  This approximation is from the paper:
 *      Discrete Differential-Geometry Operators for Triangulated 2-Manifolds
 *      Mark Meyer, Mathieu Desbrun, Peter Schroder, Alan H. Barr
 *      VisMath '02, Berlin (Germany)
 *      http://www-grail.usc.edu/pubs.html
 *
 *  Returns: %true if the operator could be evaluated, %false if the evaluation failed for some reason (@v is
 *  boundary or is the endpoint of a non-manifold edge.)
 */
bool gts_vertex_mean_curvature_normal(WVertex *v, Vec3r &Kh)
{
	real area = 0.0;

	if (!v)
		return false;

	/* this operator is not defined for boundary edges */
	if (v->isBoundary())
		return false;

	WVertex::incoming_edge_iterator itE;

	for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++)
		area += (*itE)->GetaFace()->getArea();

	Kh = Vec3r(0.0, 0.0, 0.0);

	for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++) {
		WOEdge *e = (*itE)->getPrevOnFace();
#if 0
		if ((e->GetaVertex() == v) || (e->GetbVertex() == v))
			cerr<< "BUG ";
#endif
		WVertex *v1 = e->GetaVertex();
		WVertex *v2 = e->GetbVertex();
		real temp;

		temp = cotan(v1, v, v2);
		Kh = Vec3r(Kh + temp * (v2->GetVertex() - v->GetVertex()));

		temp = cotan(v2, v, v1);
		Kh = Vec3r(Kh + temp * (v1->GetVertex() - v->GetVertex()));
	}
	if (area > 0.0) {
		Kh[0] /= 2 * area;
		Kh[1] /= 2 * area;
		Kh[2] /= 2 * area;
	}
	else {
		return false;
	}

	return true;
}
Beispiel #8
0
WEdge::WEdge(WEdge& iBrother)
{
	_paOEdge = NULL;
	_pbOEdge = NULL;
	WOEdge *aoedge = iBrother.GetaOEdge();
	WOEdge *boedge = iBrother.GetbOEdge();
	userdata = NULL;

	if (aoedge)
		//_paOEdge = new WOEdge(*aoedge);
		_paOEdge = aoedge->duplicate();
	if (boedge)
		//_pbOEdge = new WOEdge(*boedge);
		_pbOEdge = boedge->duplicate();

	_nOEdges = iBrother.GetNumberOfOEdges();
	_Id = iBrother.GetId();
	iBrother.userdata = new edgedata;
	((edgedata *)(iBrother.userdata))->_copy = this;
}
Beispiel #9
0
void compute_curvature_tensor_one_ring(WVertex *start, NormalCycle& nc)
{
	// in case we have a non-manifold vertex, skip it...
	if (start->isBoundary())
		return;

	WVertex::incoming_edge_iterator woeit = start->incoming_edges_begin();
	WVertex::incoming_edge_iterator woeitend = start->incoming_edges_end();
	for (; woeit != woeitend; ++woeit) {
		WOEdge *h = (*woeit)->twin();
		nc.accumulate_dihedral_angle(h->GetVec(), h->GetAngle());
		WOEdge *hprev = h->getPrevOnFace();
		nc.accumulate_dihedral_angle(hprev->GetVec(), hprev->GetAngle());
	}
}
Beispiel #10
0
// TODO: check optimizations:
// use marking ? (measure *timings* ...)
void compute_curvature_tensor(WVertex *start, real radius, NormalCycle& nc)
{
	// in case we have a non-manifold vertex, skip it...
	if (start->isBoundary())
		return;

	std::set<WVertex*> vertices;
	const Vec3r& O = start->GetVertex();
	std::stack<WVertex*> S;
	S.push(start);
	vertices.insert(start);
	while (!S.empty()) {
		WVertex *v = S.top();
		S.pop();
		if (v->isBoundary())
			continue;
		const Vec3r& P = v->GetVertex();
		WVertex::incoming_edge_iterator woeit = v->incoming_edges_begin();
		WVertex::incoming_edge_iterator woeitend = v->incoming_edges_end();
		for (; woeit != woeitend; ++woeit) {
			WOEdge *h = *woeit;
			if ((v == start) || h->GetVec() * (O - P) > 0.0) {
				Vec3r V(-1 * h->GetVec());
				bool isect = sphere_clip_vector(O, radius, P, V);
				assert (h->GetOwner()->GetNumberOfOEdges() == 2); // Because otherwise v->isBoundary() would be true
				nc.accumulate_dihedral_angle(V, h->GetAngle());

				if (!isect) {
					WVertex *w = h->GetaVertex();
					if (vertices.find(w) == vertices.end()) {
						vertices.insert(w);
						S.push(w);
					}
				}
			}
		}
	}
}
Beispiel #11
0
WFace *WShape::MakeFace(vector<WVertex *>& iVertexList, vector<bool>& iFaceEdgeMarksList, unsigned iMaterial,
                        WFace *face)
{
	int id = _FaceList.size();

	face->setFrsMaterialIndex(iMaterial);

	// Check whether we have a degenerated face:

	// LET'S HACK IT FOR THE TRIANGLE CASE:

	if (3 == iVertexList.size()) {
		if ((iVertexList[0] == iVertexList[1]) ||
		    (iVertexList[0] == iVertexList[2]) ||
		    (iVertexList[2] == iVertexList[1]))
		{
			cerr << "Warning: degenerated triangle detected, correcting" << endl;
			return NULL;
		}
	}

	vector<WVertex *>::iterator it;

	// compute the face normal (v1v2 ^ v1v3)
	WVertex *v1, *v2, *v3;
	it = iVertexList.begin();
	v1 = *it;
	it++;
	v2 = *it;
	it++;
	v3 = *it;

	Vec3r vector1(v2->GetVertex() - v1->GetVertex());
	Vec3r vector2(v3->GetVertex() - v1->GetVertex());

	Vec3r normal(vector1 ^ vector2);
	normal.normalize();
	face->setNormal(normal);

	vector<bool>::iterator mit = iFaceEdgeMarksList.begin();
	face->setMark(*mit);
	mit++;

	// vertex pointers used to build each edge
	vector<WVertex *>::iterator va, vb;

	va = iVertexList.begin();
	vb = va;
	for (; va != iVertexList.end(); va = vb) {
		++vb;
		// Adds va to the vertex list:
		//face->AddVertex(*va);

		WOEdge *oedge;
		if (*va == iVertexList.back())
			oedge = face->MakeEdge(*va, iVertexList.front()); //for the last (closing) edge
		else
			oedge = face->MakeEdge(*va, *vb);

		if (!oedge)
			return NULL;

		WEdge *edge = oedge->GetOwner();
		if (1 == edge->GetNumberOfOEdges()) {
			// means that we just created a new edge and that we must add it to the shape's edges list
			edge->setId(_EdgeList.size());
			AddEdge(edge);
			// compute the mean edge value:
			_meanEdgeSize += edge->GetaOEdge()->GetVec().norm();
		}

		edge->setMark(*mit);
		++mit;
	}

	// Add the face to the shape's faces list:
	face->setId(id);
	AddFace(face);

	return face;
}
Beispiel #12
0
WShape::WShape(WShape& iBrother)
{
	_Id = iBrother.GetId();
	_Name = iBrother._Name;
	_FrsMaterials = iBrother._FrsMaterials;
	_meanEdgeSize = iBrother._meanEdgeSize;
	iBrother.bbox(_min, _max);
	vector<WVertex *>& vertexList = iBrother.getVertexList();
	vector<WVertex *>::iterator v = vertexList.begin(), vend = vertexList.end();
	for (; v != vend; ++v) {
		//WVertex *newVertex = new WVertex(*(*v));
		WVertex *newVertex = (*v)->duplicate();

		newVertex->setShape(this);
		AddVertex(newVertex);
	}

	vector<WEdge *>& edgeList = iBrother.getEdgeList();
	vector<WEdge *>::iterator e = edgeList.begin(), eend = edgeList.end();
	for (; e != eend; ++e) {
		//WEdge *newEdge = new WEdge(*(*e));
		WEdge *newEdge = (*e)->duplicate();
		AddEdge(newEdge);
	}

	vector<WFace *>& faceList = iBrother.GetFaceList();
	vector<WFace *>::iterator f = faceList.begin(), fend = faceList.end();
	for (; f != fend; ++f) {
		//WFace *newFace = new WFace(*(*f));
		WFace *newFace = (*f)->duplicate();
		AddFace(newFace);
	}

	// update all pointed addresses thanks to the newly created objects:
	vend = _VertexList.end();
	for (v = _VertexList.begin(); v != vend; ++v) {
		const vector<WEdge *>& vedgeList = (*v)->GetEdges();
		vector<WEdge *> newvedgelist;
		unsigned int i;
		for (i = 0; i < vedgeList.size(); i++) {
			WEdge *current = vedgeList[i];
			edgedata *currentvedata = (edgedata *)current->userdata;
			newvedgelist.push_back(currentvedata->_copy);
		}
		(*v)->setEdges(newvedgelist);
	}

	eend = _EdgeList.end();
	for (e = _EdgeList.begin(); e != eend; ++e) {
		// update aOedge:
		WOEdge *aoEdge = (*e)->GetaOEdge();
		aoEdge->setaVertex(((vertexdata *)(aoEdge->GetaVertex()->userdata))->_copy);
		aoEdge->setbVertex(((vertexdata *)(aoEdge->GetbVertex()->userdata))->_copy);
		if (aoEdge->GetaFace())
			aoEdge->setaFace(((facedata *)(aoEdge->GetaFace()->userdata))->_copy);
		aoEdge->setbFace(((facedata *)(aoEdge->GetbFace()->userdata))->_copy);
		aoEdge->setOwner(((edgedata *)(aoEdge->GetOwner()->userdata))->_copy);

		// update bOedge:
		WOEdge *boEdge = (*e)->GetbOEdge();
		if (boEdge) {
			boEdge->setaVertex(((vertexdata *)(boEdge->GetaVertex()->userdata))->_copy);
			boEdge->setbVertex(((vertexdata *)(boEdge->GetbVertex()->userdata))->_copy);
			if (boEdge->GetaFace())
				boEdge->setaFace(((facedata *)(boEdge->GetaFace()->userdata))->_copy);
			boEdge->setbFace(((facedata *)(boEdge->GetbFace()->userdata))->_copy);
			boEdge->setOwner(((edgedata *)(boEdge->GetOwner()->userdata))->_copy);
		}
	}

	fend = _FaceList.end();
	for (f = _FaceList.begin(); f != fend; ++f) {
		unsigned int i;
		const vector<WOEdge *>& oedgeList = (*f)->getEdgeList();
		vector<WOEdge *> newoedgelist;

		unsigned int n = oedgeList.size();
		for (i = 0; i < n; i++) {
			WOEdge *current = oedgeList[i];
			oedgedata *currentoedata = (oedgedata *)current->userdata;
			newoedgelist.push_back(currentoedata->_copy);
			//oedgeList[i] = currentoedata->_copy;
			//oedgeList[i] = ((oedgedata *)(oedgeList[i]->userdata))->_copy;
		}
		(*f)->setEdgeList(newoedgelist);
	}

	// Free all memory (arghh!)
	// Vertex
	vend = iBrother.getVertexList().end();
	for (v = iBrother.getVertexList().begin(); v != vend; ++v) {
		delete (vertexdata *)((*v)->userdata);
		(*v)->userdata = NULL;
	}

	// Edges and OEdges:
	eend = iBrother.getEdgeList().end();
	for (e = iBrother.getEdgeList().begin(); e != eend; ++e) {
		delete (edgedata *)((*e)->userdata);
		(*e)->userdata = NULL;
		// OEdge a:
		delete (oedgedata *)((*e)->GetaOEdge()->userdata);
		(*e)->GetaOEdge()->userdata = NULL;
		// OEdge b:
		WOEdge *oedgeb = (*e)->GetbOEdge();
		if (oedgeb) {
			delete (oedgedata *)(oedgeb->userdata);
			oedgeb->userdata = NULL;
		}
	}

	// Faces
	fend = iBrother.GetFaceList().end();
	for (f = iBrother.GetFaceList().begin(); f != fend; ++f) {
		delete (facedata *)((*f)->userdata);
		(*f)->userdata = NULL;
	}
}
Beispiel #13
0
WOEdge *WFace::MakeEdge(WVertex *v1, WVertex *v2)
{
	// First check whether the same oriented edge already exists or not:
	vector<WEdge *>& v1Edges = v1->GetEdges();
	for (vector<WEdge*>::iterator it1 = v1Edges.begin(), end = v1Edges.end(); it1 != end; it1++) {
		WEdge *we = (*it1);
		WOEdge *woea = we->GetaOEdge();

		//if ((*it1)->GetbVertex() == v2) {
		if ((woea->GetaVertex() == v1) && (woea->GetbVertex() == v2)) {
			// The oriented edge already exists
			cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId() << " appears twice, correcting" << endl;
			// Adds the edge to the face
			//AddEdge((*it1)->GetaOEdge());
			AddEdge(woea);
			(*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges() + 1);
			//sets these vertices as border:
			v1->setBorder(true);
			v2->setBorder(true);
			//return (*it1)->GetaOEdge();
			return woea;
		}

		WOEdge *woeb = we->GetbOEdge();
		//if ((*it1)->GetbVertex() == v2)
		if (woeb && (woeb->GetaVertex() == v1) && (woeb->GetbVertex() == v2)) {
			// The oriented edge already exists
			cerr << "Warning: edge " << v1->GetId() << " - " << v2->GetId() << " appears twice, correcting" << endl;
			// Adds the edge to the face
			//AddEdge((*it1)->GetaOEdge());
			AddEdge(woeb);
			(*it1)->setNumberOfOEdges((*it1)->GetNumberOfOEdges() + 1);
			//sets these vertices as border:
			v1->setBorder(true);
			v2->setBorder(true);
			//return (*it1)->GetaOEdge();
			return woeb;
		}
	}

	// the oriented edge we're about to build
	WOEdge *pOEdge = new WOEdge;
	// The edge containing the oriented edge.
	WEdge *edge;

	// checks whether this edge already exists or not
	// If it exists, it points outward v2
	bool exist = false;
	WOEdge *pInvertEdge = NULL; // The inverted edge if it exists
	vector<WEdge *>& v2Edges = v2->GetEdges();
	vector<WEdge *>::iterator it;
	for (it = v2Edges.begin(); it != v2Edges.end(); it++) {
		if ((*it)->GetbVertex() == v1) {
			// The invert edge already exists
			exist = true;
			pInvertEdge = (*it)->GetaOEdge();
			break;
		}
	}

	//DEBUG:
	if (true == exist) { // The invert edge already exists
		// Retrieves the corresponding edge
		edge = pInvertEdge->GetOwner();

		// Sets the a Face (retrieved from pInvertEdge
		pOEdge->setaFace(pInvertEdge->GetbFace());

		// Updates the invert edge:
		pInvertEdge->setaFace(this);
	}
	else { // The invert edge does not exist yet
		// we must create a new edge
		//edge = new WEdge;
		edge = instanciateEdge();

		// updates the a,b vertex edges list:
		v1->AddEdge(edge);
		v2->AddEdge(edge);
	}

	pOEdge->setOwner(edge);
	// Add the vertices:
	pOEdge->setaVertex(v1);
	pOEdge->setbVertex(v2);

	// Debug:
	if (v1->GetId() == v2->GetId())
		cerr << "Warning: edge " << this << " null with vertex " << v1->GetId() << endl;

	edge->AddOEdge(pOEdge);
	//edge->setNumberOfOEdges(edge->GetNumberOfOEdges() + 1);

	// Add this face (the b face)
	pOEdge->setbFace(this);

	// Adds the edge to the face
	AddEdge(pOEdge);

	return pOEdge;
}
Beispiel #14
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.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
}
Beispiel #15
0
/*! gts_vertex_principal_directions:
 *  @v: a #WVertex.
 *  @s: a #GtsSurface.
 *  @Kh: mean curvature normal (a #Vec3r).
 *  @Kg: Gaussian curvature (a real).
 *  @e1: first principal curvature direction (direction of largest curvature).
 *  @e2: second principal curvature direction.
 *
 *  Computes the principal curvature directions at a point given @Kh and @Kg, the mean curvature normal and
 *  Gaussian curvatures at that point, computed with gts_vertex_mean_curvature_normal() and
 *  gts_vertex_gaussian_curvature(), respectively.
 *
 *  Note that this computation is very approximate and tends to be unstable. Smoothing of the surface or the principal
 *  directions may be necessary to achieve reasonable results.
 */
void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, Vec3r &e2)
{
	Vec3r N;
	real normKh;

	Vec3r basis1, basis2, d, eig;
	real ve2, vdotN;
	real aterm_da, bterm_da, cterm_da, const_da;
	real aterm_db, bterm_db, cterm_db, const_db;
	real a, b, c;
	real K1, K2;
	real *weights, *kappas, *d1s, *d2s;
	int edge_count;
	real err_e1, err_e2;
	int e;
	WVertex::incoming_edge_iterator itE;

	/* compute unit normal */
	normKh = Kh.norm();

	if (normKh > 0.0) {
		Kh.normalize();
	}
	else {
		/* This vertex is a point of zero mean curvature (flat or saddle point). Compute a normal by averaging
		 * the adjacent triangles
		 */
		N[0] = N[1] = N[2] = 0.0;

		for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++)
			N = Vec3r(N + (*itE)->GetaFace()->GetNormal());
		real normN = N.norm();
		if (normN <= 0.0)
			return;
		N.normalize();
	}

	/* construct a basis from N: */
	/* set basis1 to any component not the largest of N */
	basis1[0] =  basis1[1] =  basis1[2] = 0.0;
	if (fabs (N[0]) > fabs (N[1]))
		basis1[1] = 1.0;
	else
		basis1[0] = 1.0;

	/* make basis2 orthogonal to N */
	basis2 = (N ^ basis1);
	basis2.normalize();

	/* make basis1 orthogonal to N and basis2 */
	basis1 = (N ^ basis2);
	basis1.normalize();

	aterm_da = bterm_da = cterm_da = const_da = 0.0;
	aterm_db = bterm_db = cterm_db = const_db = 0.0;
	int nb_edges = v->GetEdges().size();

	weights = (real *)malloc(sizeof(real) * nb_edges);
	kappas = (real *)malloc(sizeof(real) * nb_edges);
	d1s = (real *)malloc(sizeof(real) * nb_edges);
	d2s = (real *)malloc(sizeof(real) * nb_edges);
	edge_count = 0;

	for (itE = v->incoming_edges_begin(); itE != v->incoming_edges_end(); itE++) {
		WOEdge *e;
		WFace *f1, *f2;
		real weight, kappa, d1, d2;
		Vec3r vec_edge;
		if (!*itE)
			continue;
		e = *itE;

		/* since this vertex passed the tests in gts_vertex_mean_curvature_normal(), this should be true. */
		//g_assert(gts_edge_face_number (e, s) == 2);

		/* identify the two triangles bordering e in s */
		f1 = e->GetaFace();
		f2 = e->GetbFace();

		/* We are solving for the values of the curvature tensor
		 *     B = [ a b ; b c ].
		 *  The computations here are from section 5 of [Meyer et al 2002].
		 *
		 *  The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed
		 *  by setting the derivatives of the error E to zero (section 5.3).
		 *
		 *  Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002]
		 *  has the equation a + b = norm(Kh), but I'm almost positive this is incorrect).
		 *
		 *  Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale
		 *  factor because the solution of the linear equations doesn't rely on it.
		 *
		 *  The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy
		 *  terms that are the constant factors in the equations.
		 */

		/* find the vector from v along edge e */
		vec_edge = Vec3r(-1 * e->GetVec());

		ve2 = vec_edge.squareNorm();
		vdotN = vec_edge * N;

		/* section 5.2 - There is a typo in the computation of kappa. The edges should be x_j-x_i. */
		kappa = 2.0 * vdotN / ve2;

		/* section 5.2 */

		/* I don't like performing a minimization where some of the weights can be negative (as can be the case
		 *  if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */
		weight = 0.0;
		if (!triangle_obtuse(v, f1)) {
			weight += ve2 * cotan(f1->GetNextOEdge(e->twin())->GetbVertex(), e->GetaVertex(), e->GetbVertex()) / 8.0;
		}
		else {
			if (angle_obtuse(v, f1)) {
				weight += ve2 * f1->getArea() / 4.0;
			}
			else {
				weight += ve2 * f1->getArea() / 8.0;
			}
		}

		if (!triangle_obtuse(v, f2)) {
			weight += ve2 * cotan (f2->GetNextOEdge(e)->GetbVertex(), e->GetaVertex(), e->GetbVertex()) / 8.0;
		}
		else {
			if (angle_obtuse(v, f2)) {
				weight += ve2 * f1->getArea() / 4.0;
			}
			else {
				weight += ve2 * f1->getArea() / 8.0;
			}
		}

		/* projection of edge perpendicular to N (section 5.3) */
		d[0] = vec_edge[0] - vdotN * N[0];
		d[1] = vec_edge[1] - vdotN * N[1];
		d[2] = vec_edge[2] - vdotN * N[2];
		d.normalize();

		/* not explicit in the paper, but necessary. Move d to 2D basis. */
		d1 = d * basis1;
		d2 = d * basis2;

		/* store off the curvature, direction of edge, and weights for later use */
		weights[edge_count] = weight;
		kappas[edge_count] = kappa;
		d1s[edge_count] = d1;
		d2s[edge_count] = d2;
		edge_count++;

		/* Finally, update the linear equations */
		aterm_da += weight * d1 * d1 * d1 * d1;
		bterm_da += weight * d1 * d1 * 2 * d1 * d2;
		cterm_da += weight * d1 * d1 * d2 * d2;
		const_da += weight * d1 * d1 * (-kappa);

		aterm_db += weight * d1 * d2 * d1 * d1;
		bterm_db += weight * d1 * d2 * 2 * d1 * d2;
		cterm_db += weight * d1 * d2 * d2 * d2;
		const_db += weight * d1 * d2 * (-kappa);
	}

	/* now use the identity (Section 5.3) a + c = |Kh| = 2 * kappa_h */
	aterm_da -= cterm_da;
	const_da += cterm_da * normKh;

	aterm_db -= cterm_db;
	const_db += cterm_db * normKh;

	/* check for solvability of the linear system */
	if (((aterm_da * bterm_db - aterm_db * bterm_da) != 0.0) && ((const_da != 0.0) || (const_db != 0.0))) {
		linsolve(aterm_da, bterm_da, -const_da, aterm_db, bterm_db, -const_db, &a, &b);

		c = normKh - a;

		eigenvector(a, b, c, eig);
	}
	else {
		/* region of v is planar */
		eig[0] = 1.0;
		eig[1] = 0.0;
	}

	/* Although the eigenvectors of B are good estimates of the principal directions, it seems that which one is
	 * attached to which curvature direction is a bit arbitrary. This may be a bug in my implementation, or just
	 * a side-effect of the inaccuracy of B due to the discrete nature of the sampling.
	 *
	 * To overcome this behavior, we'll evaluate which assignment best matches the given eigenvectors by comparing
	 * the curvature estimates computed above and the curvatures calculated from the discrete differential operators.
	 */

	gts_vertex_principal_curvatures(0.5 * normKh, Kg, &K1, &K2);

	err_e1 = err_e2 = 0.0;
	/* loop through the values previously saved */
	for (e = 0; e < edge_count; e++) {
		real weight, kappa, d1, d2;
		real temp1, temp2;
		real delta;

		weight = weights[e];
		kappa = kappas[e];
		d1 = d1s[e];
		d2 = d2s[e];

		temp1 = fabs (eig[0] * d1 + eig[1] * d2);
		temp1 = temp1 * temp1;
		temp2 = fabs (eig[1] * d1 - eig[0] * d2);
		temp2 = temp2 * temp2;

		/* err_e1 is for K1 associated with e1 */
		delta = K1 * temp1 + K2 * temp2 - kappa;
		err_e1 += weight * delta * delta;

		/* err_e2 is for K1 associated with e2 */
		delta = K2 * temp1 + K1 * temp2 - kappa;
		err_e2 += weight * delta * delta;
	}
	free (weights);
	free (kappas);
	free (d1s);
	free (d2s);

	/* rotate eig by a right angle if that would decrease the error */
	if (err_e2 < err_e1) {
		real temp = eig[0];

		eig[0] = eig[1];
		eig[1] = -temp;
	}

	e1[0] = eig[0] * basis1[0] + eig[1] * basis2[0];
	e1[1] = eig[0] * basis1[1] + eig[1] * basis2[1];
	e1[2] = eig[0] * basis1[2] + eig[1] * basis2[2];
	e1.normalize();

	/* make N,e1,e2 a right handed coordinate sytem */
	e2 =  N ^ e1;
	e2.normalize();
}
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);
}