Skip to main content
  • Home
  • Development
  • Documentation
  • Donate
  • Operational login
  • Browse the archive

swh logo
SoftwareHeritage
Software
Heritage
Archive
Features
  • Search

  • Downloads

  • Save code now

  • Add forge now

  • Help

  • e31fa09
  • /
  • src
  • /
  • external
  • /
  • ArcSim
  • /
  • geometry.cpp
Raw File Download

To reference or cite the objects present in the Software Heritage archive, permalinks based on SoftWare Hash IDentifiers (SWHIDs) must be used.
Select below a type of object currently browsed in order to display its associated SWHID and permalink.

  • content
  • directory
content badge
swh:1:cnt:205defa08fc4f1a454495f0fc11c96a95ba0129f
directory badge
swh:1:dir:70754d5bbbcb118b85e3fd43533ce31be60ab86b

This interface enables to generate software citations, provided that the root directory of browsed objects contains a citation.cff or codemeta.json file.
Select below a type of object currently browsed in order to generate citations for them.

  • content
  • directory
(requires biblatex-software package)
Generating citation ...
(requires biblatex-software package)
Generating citation ...
geometry.cpp
/*
Copyright ©2013 The Regents of the University of California
(Regents). All Rights Reserved. Permission to use, copy, modify, and
distribute this software and its documentation for educational,
research, and not-for-profit purposes, without fee and without a
signed licensing agreement, is hereby granted, provided that the
above copyright notice, this paragraph and the following two
paragraphs appear in all copies, modifications, and
distributions. Contact The Office of Technology Licensing, UC
Berkeley, 2150 Shattuck Avenue, Suite 510, Berkeley, CA 94720-1620,
(510) 643-7201, for commercial licensing opportunities.

IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT,
INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING
LOST PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS
DOCUMENTATION, EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY
OF SUCH DAMAGE.

REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING
DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS
IS". REGENTS HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT,
UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
*/

#include "geometry.hpp"
#include <cstdlib>

using namespace std;

double signed_vf_distance(const Vec3 &x,
	const Vec3 &y0, const Vec3 &y1, const Vec3 &y2,
	Vec3 *n, double *w) {
	Vec3 _n; if (!n) n = &_n;
	double _w[4]; if (!w) w = _w;
	*n = cross(normalize(y1 - y0), normalize(y2 - y0));
	if (norm2(*n) < 1e-6)
		return infinity;
	*n = normalize(*n);
	double h = dot(x - y0, *n);
	double b0 = stp(y1 - x, y2 - x, *n),
		b1 = stp(y2 - x, y0 - x, *n),
		b2 = stp(y0 - x, y1 - x, *n);
	w[0] = 1;
	w[1] = -b0 / (b0 + b1 + b2);
	w[2] = -b1 / (b0 + b1 + b2);
	w[3] = -b2 / (b0 + b1 + b2);
	return h;
}

double signed_ve_distance(const Vec3 &x, const Vec3 &y0, const Vec3 &y1,
	Vec3* n, double *w) {
	Vec3 e = y1 - y0;
	double d = dot(x - y0, e) / norm2(e);
	if (d < 0 || d > 1.0)
		return infinity;
	if (w) {
		w[0] = 1;
		w[1] = -(1.0 - d);
		w[2] = -d;
		w[3] = 0;
	}
	Vec3 dist = x - (y0 + d*e);
	double l = norm(dist);
	if (n && fabs(l) > 1e-16) *n = dist / l;
	return l;
}

double signed_ee_distance(const Vec3 &x0, const Vec3 &x1,
	const Vec3 &y0, const Vec3 &y1,
	Vec3 *n, double *w) {
	Vec3 _n; if (!n) n = &_n;
	double _w[4]; if (!w) w = _w;
	*n = cross(normalize(x1 - x0), normalize(y1 - y0));
	if (norm2(*n) < 1e-8) {
		// special case: parallel lines
		Vec3 e0 = normalize(x1 - x0), e1 = normalize(y1 - y0);

		double p0min = dot(x0, e0), p0max = dot(x1, e0), p1min = dot(y0, e0), p1max = dot(y1, e0);
		if (p1max < p1min) swap(p1max, p1min);

		double a = max(p0min, p1min), b = min(p0max, p1max), c = 0.5*(a + b);
		if (a > b) return infinity;

		Vec3 d = (y0 - x0) - dot(y0 - x0, e0)*e0;

		if (n) *n = normalize(-d);
		if (w) {
			w[1] = (c - dot(x0, e0)) / norm(x1 - x0);
			w[0] = 1.0 - w[1];
			w[3] = -(dot(e0, e1)*c - dot(y0, e1)) / norm(y1 - y0);
			w[2] = -1.0 - w[3];
		}
		return norm(d);
	}
	*n = normalize(*n);
	double h = dot(x0 - y0, *n);
	double a0 = stp(y1 - x1, y0 - x1, *n), a1 = stp(y0 - x0, y1 - x0, *n),
		b0 = stp(x0 - y1, x1 - y1, *n), b1 = stp(x1 - y0, x0 - y0, *n);
	w[0] = a0 / (a0 + a1);
	w[1] = a1 / (a0 + a1);
	w[2] = -b0 / (b0 + b1);
	w[3] = -b1 / (b0 + b1);
	return h;
}

bool set_unsigned_ve_distance(const Vec3 &x, const Vec3 &y0, const Vec3 &y1,
	double *_d, Vec3 *_n,
	double *_wx, double *_wy0, double *_wy1) {
	double t = clamp(dot(x - y0, y1 - y0) / dot(y1 - y0, y1 - y0), 0., 1.);
	Vec3 y = y0 + t*(y1 - y0);
	double d = norm(x - y);
	if (d < *_d) {
		*_d = d;
		*_n = normalize(x - y);
		*_wx = 1;
		*_wy0 = 1 - t;
		*_wy1 = t;
		return true;
	}
	return false;
}

bool set_unsigned_vf_distance(const Vec3 &x,
	const Vec3 &y0, const Vec3 &y1, const Vec3 &y2,
	double *_d, Vec3 *_n,
	double *_wx,
	double *_wy0, double *_wy1, double *_wy2) {
	Vec3 n = normalize(cross(normalize(y1 - y0), normalize(y2 - y0)));
	double d = abs(dot(x - y0, n));
	double b0 = stp(y1 - x, y2 - x, n),
		b1 = stp(y2 - x, y0 - x, n),
		b2 = stp(y0 - x, y1 - x, n);
	if (d < *_d && b0 >= 0 && b1 >= 0 && b2 >= 0) {
		*_d = d;
		*_n = n;
		*_wx = 1;
		*_wy0 = -b0 / (b0 + b1 + b2);
		*_wy1 = -b1 / (b0 + b1 + b2);
		*_wy2 = -b2 / (b0 + b1 + b2);
		return true;
	}
	bool success = false;
	if (b0 < 0
		&& set_unsigned_ve_distance(x, y1, y2, _d, _n, _wx, _wy1, _wy2)) {
		success = true;
		*_wy0 = 0;
	}
	if (b1 < 0
		&& set_unsigned_ve_distance(x, y2, y0, _d, _n, _wx, _wy2, _wy0)) {
		success = true;
		*_wy1 = 0;
	}
	if (b2 < 0
		&& set_unsigned_ve_distance(x, y0, y1, _d, _n, _wx, _wy0, _wy1)) {
		success = true;
		*_wy2 = 0;
	}
	return success;
}

bool set_unsigned_ee_distance(const Vec3 &x0, const Vec3 &x1,
	const Vec3 &y0, const Vec3 &y1,
	double *_d, Vec3 *_n,
	double *_wx0, double *_wx1,
	double *_wy0, double *_wy1) {
	Vec3 n = normalize(cross(normalize(x1 - x0), normalize(y1 - y0)));
	double d = abs(dot(x0 - y0, n));
	double a0 = stp(y1 - x1, y0 - x1, n), a1 = stp(y0 - x0, y1 - x0, n),
		b0 = stp(x0 - y1, x1 - y1, n), b1 = stp(x1 - y0, x0 - y0, n);
	if (d < *_d && a0 >= 0 && a1 >= 0 && b0 >= 0 && b1 >= 0) {
		*_d = d;
		*_n = n;
		*_wx0 = a0 / (a0 + a1);
		*_wx1 = a1 / (a0 + a1);
		*_wy0 = -b0 / (b0 + b1);
		*_wy1 = -b1 / (b0 + b1);
		return true;
	}
	bool success = false;
	if (a0 < 0
		&& set_unsigned_ve_distance(x1, y0, y1, _d, _n, _wx1, _wy0, _wy1)) {
		success = true;
		*_wx0 = 0;
	}
	if (a1 < 0
		&& set_unsigned_ve_distance(x0, y0, y1, _d, _n, _wx0, _wy0, _wy1)) {
		success = true;
		*_wx1 = 0;
	}
	if (b0 < 0
		&& set_unsigned_ve_distance(y1, x0, x1, _d, _n, _wy1, _wx0, _wx1)) {
		success = true;
		*_wy0 = 0;
		*_n = -*_n;
	}
	if (b1 < 0
		&& set_unsigned_ve_distance(y0, x0, x1, _d, _n, _wy0, _wx0, _wx1)) {
		success = true;
		*_wy1 = 0;
		*_n = -*_n;
	}
	return success;
}

double unsigned_vf_distance(const Vec3 &x,
	const Vec3 &y0, const Vec3 &y1, const Vec3 &y2,
	Vec3 *n, double w[4]) {
	Vec3 _n; if (!n) n = &_n;
	double _w[4]; if (!w) w = _w;
	double d = infinity;
	set_unsigned_vf_distance(x, y0, y1, y2, &d, n, &w[0], &w[1], &w[2], &w[3]);
	return d;
}

double unsigned_ee_distance(const Vec3 &x0, const Vec3 &x1,
	const Vec3 &y0, const Vec3 &y1,
	Vec3 *n, double w[4]) {
	Vec3 _n; if (!n) n = &_n;
	double _w[4]; if (!w) w = _w;
	double d = infinity;
	set_unsigned_ee_distance(x0, x1, y0, y1, &d, n, &w[0], &w[1], &w[2], &w[3]);
	return d;
}

// NICK
double unsigned_vv_distance(const Vec3 &x, const Vec3 &y) {
	return sqrt(pow(y[0] - x[0],2) + pow(y[1] - x[1], 2));
}

double incedent_angle(const Vert* v, const Face* f) {
	Vec3 x = v->u;
	Vec3 y;
	Vec3 z;
	if (f->v[0] == v) {
		y = f->v[1]->u;
		z = f->v[2]->u;
	}
	else if (f->v[1] == v) {
		y = f->v[0]->u;
		z = f->v[2]->u;
	}
	else if (f->v[2] == v) {
		y = f->v[0]->u;
		z = f->v[1]->u;
	}
	Vec3 a = y - x;
	Vec3 b = z - x;
	return acos(dot(a, b) / (norm(a) * norm(b)));
}

Vec3 get_barycentric_coords(const Vec2& point, const Face* f) {
	// WHY IS THERE A WARNING HERE?
	//cout << "warning bary" << endl;
	// Compute vectors        
	Vec2 v0 = reduce_xy(f->v[0]->u - f->v[2]->u);
	Vec2 v1 = reduce_xy(f->v[1]->u - f->v[2]->u);
	Vec2 v2 = point - reduce_xy(f->v[2]->u);
	// Compute dot products
	double dot00 = dot(v0, v0);
	double dot01 = dot(v0, v1);
	double dot02 = dot(v0, v2);
	double dot11 = dot(v1, v1);
	double dot12 = dot(v1, v2);
	// Compute barycentric coordinates
	double invDenom = 1.f / (dot00 * dot11 - dot01 * dot01);
	double u = (dot11 * dot02 - dot01 * dot12) * invDenom;
	double v = (dot00 * dot12 - dot01 * dot02) * invDenom;
	return Vec3(u, v, 1 - u - v);
}

// Is the point within the face?
// Adapted from http://www.blackpawn.com/texts/pointinpoly/default.html
bool is_inside(const Vec2& point, const Face* f) {
	Vec3 bary = get_barycentric_coords(point, f);
	//printf("UV: %f, %f\n", u, v);
	// Check if point is in triangle
	// 10*epsilon: want to be robust for borders
	return ((bary[0] >= -10 * EPSILON) && (bary[1] >= -10 * EPSILON) && (bary[2] >= -100 * EPSILON));
}

// Gets the face that surrounds point u in material space
Face* get_enclosing_face(const Mesh& mesh, const Vec2& u,
	Face *starting_face_hint) {
	for (int f = 0; f < (int)mesh.faces.size(); f++)
		if (is_inside(u, mesh.faces[f]))
			return mesh.faces[f];
	return NULL;
}

template <Space s> Vec3 normal(const Face *face) {
	const Vec3 &x0 = pos<s>(face->v[0]),
		&x1 = pos<s>(face->v[1]),
		&x2 = pos<s>(face->v[2]);
	return normalize(cross(x1 - x0, x2 - x0));
}
template Vec3 normal<MS>(const Face *face);
template Vec3 normal<PS>(const Face *face);
template Vec3 normal<WS>(const Face *face);

template <Space s> Vec3 normal(const Node* node) {
	Vec3 n(0);
	for (size_t v = 0; v < node->verts.size(); v++) {
		const Vert *vert = node->verts[v];
		const vector<Face*> &adjfs = vert->adjf;
		for (size_t i = 0; i < adjfs.size(); i++) {
			Face const* face = adjfs[i];
			int j = find(vert, face->v), j1 = (j + 1) % 3, j2 = (j + 2) % 3;
			Vec3 e1 = pos<s>(face->v[j1]) - pos<s>(vert),
				e2 = pos<s>(face->v[j2]) - pos<s>(vert);
			n += cross(e1, e2) / (2 * norm2(e1)*norm2(e2));
		}
	}
	return normalize(n);
}
template Vec3 normal<MS>(const Node*);
template Vec3 normal<WS>(const Node*);

double dihedral_angle(const Vec3& p0, const Vec3& p1, const Vec3& n0, const Vec3& n1) {
	Vec3 e = normalize(p1 - p0);
	if (norm2(e) == 0) return 0;
	if (norm2(n0) == 0 || norm2(n1) == 0) return 0;
	double cosine = dot(n0, n1), sine = dot(e, cross(n0, n1));
	double theta = atan2(sine, cosine);
	return theta;
}

template <Space s> double dihedral_angle(const Edge *edge) {
	// if (!hinge.edge[0] || !hinge.edge[1]) return 0;
	// const Edge *edge0 = hinge.edge[0], *edge1 = hinge.edge[1];
	// int s0 = hinge.s[0], s1 = hinge.s[1];
	if (!edge->adjf[0] || !edge->adjf[1])
		return 0;
	if (s == MS && is_seam(edge))
		return 0;
	Vec3 e = normalize(pos<s>(edge_vert(edge, 0, 0)) - pos<s>(edge_vert(edge, 0, 1)));
	if (norm2(e) == 0) return 0;
	Vec3 n0 = normal<s>(edge->adjf[0]), n1 = normal<s>(edge->adjf[1]);
	if (norm2(n0) == 0 || norm2(n1) == 0) return 0;
	double cosine = dot(n0, n1), sine = dot(e, cross(n0, n1));
	double theta = atan2(sine, cosine);
	return theta;
}
template double dihedral_angle<MS>(const Edge *edge);
template double dihedral_angle<PS>(const Edge *edge);
template double dihedral_angle<WS>(const Edge *edge);

template <Space s> Mat2x2 projected_curvature(const Face *face, const Mat2x3& base) {
	Mat2x2 S;
	for (int e = 0; e < 3; e++) {
		Vec2 e_mat = base * (face->v[PREV(e)]->u - face->v[NEXT(e)]->u),
			t_mat = perp(normalize(e_mat));

		// TODO: don't refine over sharp creases
		//if ((edge->v[0]->flag & edge->v[1]->flag & Vert::SharpCrease) != 0)
		//    continue;
		double theta = dihedral_angle<s>(face->adje[e]);
		S -= 1 / 2.*theta*norm(e_mat)*outer(t_mat, t_mat);
	}
	S /= face->a;
	return S;
}
template Mat2x2 projected_curvature<PS>(const Face *face, const Mat2x3&);
template Mat2x2 projected_curvature<WS>(const Face *face, const Mat2x3&);

template <Space s> Mat3x3 curvature(const Face *face) {
	Mat3x3 S;
	Vec3 n = normal<MS>(face);
	for (int e = 0; e < 3; e++) {
		Vec3 e_mat = face->v[PREV(e)]->u - face->v[NEXT(e)]->u,
			t_mat = cross(normalize(e_mat), n);

		// TODO: don't refine over sharp creases
		//if ((edge->v[0]->flag & edge->v[1]->flag & Vert::SharpCrease) != 0)
		//    continue;
		double theta = dihedral_angle<s>(face->adje[e]);
		S -= 1 / 2.*theta*norm(e_mat)*outer(t_mat, t_mat);
	}
	S /= face->a;
	return S;
}
template Mat3x3 curvature<MS>(const Face *face);
template Mat3x3 curvature<PS>(const Face *face);
template Mat3x3 curvature<WS>(const Face *face);

double aspect(const Vec3& u0, const Vec3& u1, const Vec3& u2) {
	double perimeter = norm(u0 - u1) + norm(u1 - u2) + norm(u2 - u0);
	return 12 * sqrt(3)* 0.5 * norm(cross(u1 - u0, u2 - u0)) / sq(perimeter);
}

double get_angle(const Vec3& u, const Vec3& v) {
	return acos(clamp(dot(normalize(u), normalize(v)), -1.0, 1.0));
}

// Planes

template<Space s>
Plane plane_fit(const Mesh& mesh) {
	int num = 0;
	Vec3 center(0);
	for (int i = 0; i<mesh.verts.size(); i++) {
		num++;
		center += pos<s>(mesh.verts[i]);
	}
	center *= 1.0 / num;

	Mat3x3 M(0);
	for (int i = 0; i<mesh.verts.size(); i++) {
		Vec3 p = pos<s>(mesh.verts[i]) - center;
		M += outer(p, p);
	}
	Eig<3> eig = eigen_decomposition(M);
	return Plane(center, eig.Q.col(2));
}

Mat3x3 local_base(const Vec3& normal) {
	//Vec3 u = (dot(normal, Vec3(1, 0, 0)) > dot(normal, Vec3(0, 0, 1))) ? Vec3(0, 0, 1) : Vec3(1, 0, 0);
	Vec3 u = (abs(normal[2]) < 1e-6) ? Vec3(0, 0, 1) : Vec3(1, 0, 0);
	u = normalize(u - dot(u, normal)*normal);
	Vec3 v = cross(normal, u);
	return Mat3x3(u, v, normal);
}

template Plane plane_fit<MS>(const Mesh&);
template Plane plane_fit<WS>(const Mesh&);

// Intersection

// triangle x_I, ray x+t*d
bool triangle_ray_test(const Vec3 &x0, const Vec3& x1, const Vec3& x2,
	const Vec3 &s, const Vec3& d, double& z, Vec3* bary) {
	Vec3 e1 = x1 - x0, e2 = x2 - x0, t = s - x0;
	Vec3 p = cross(d, e2), q = cross(t, e1);
	double div = dot(p, e1);
	if (fabs(div) < 1e-18) return false;

	double idiv = 1.0 / div;
	double u = idiv * dot(p, t), v = idiv * dot(q, d);

	if (u<-1e-6 || v<-1e-6 || (u + v - 1.0) > 1e-6) return false;
	z = idiv * dot(q, e2);
	if (bary)
		*bary = Vec3((1.0 - u - v), u, v);
	return true;
}

back to top

Software Heritage — Copyright (C) 2015–2026, The Software Heritage developers. License: GNU AGPLv3+.
The source code of Software Heritage itself is available on our development forge.
The source code files archived by Software Heritage are available under their own copyright and licenses.
Terms of use: Archive access, API— Content policy— Contact— JavaScript license information— Web API