Пример #1
0
/**
  *find the tangential points from a given point, i.e., the tangent lines should pass
  * the given point and tangential points
  *
  *Author: Dongxu Li
  */
RS_VectorSolutions RS_Circle::getTangentPoint(const RS_Vector& point) const {
    RS_VectorSolutions ret;
    double r2(getRadius()*getRadius());
    if(r2<RS_TOLERANCE*RS_TOLERANCE) return ret; //circle too small
    RS_Vector vp(point-getCenter());
    double c2(vp.squared());
    if(c2<r2-getRadius()*2.*RS_TOLERANCE) {
        //inside point, no tangential point
        return ret;
    }
    if(c2>r2+getRadius()*2.*RS_TOLERANCE) {
        //external point
        RS_Vector vp1(-vp.y,vp.x);
        vp1*=getRadius()*sqrt(c2-r2)/c2;
        vp *= r2/c2;
        vp += getCenter();
        if(vp1.squared()>RS_TOLERANCE*RS_TOLERANCE) {
            ret.push_back(vp+vp1);
            ret.push_back(vp-vp1);
            return ret;
        }
    }
    ret.push_back(point);
    return ret;
}
Пример #2
0
RS_Vector RS_Spline::getNearestEndpoint(const RS_Vector& coord,
                                        double* dist)const {
    double minDist = RS_MAXDOUBLE;
    RS_Vector ret(false);
    if(! data.closed) { // no endpoint for closed spline
       RS_Vector vp1(getStartpoint());
       RS_Vector vp2(getEndpoint());
       double d1( (coord-vp1).squared());
       double d2( (coord-vp2).squared());
       if( d1<d2){
           ret=vp1;
           minDist=sqrt(d1);
       }else{
           ret=vp2;
           minDist=sqrt(d2);
       }
//        for (int i=0; i<data.controlPoints.count(); i++) {
//            d = (data.controlPoints.at(i)).distanceTo(coord);

//            if (d<minDist) {
//                minDist = d;
//                ret = data.controlPoints.at(i);
//            }
//        }
    }
	if (dist!=nullptr) {
        *dist = minDist;
    }
    return ret;
}
Пример #3
0
double Cara::getAnguloMax(Malla *malla) {
	assert(malla != 0);
	//obtenemos los indices de los arcos de la cara
	Vect normal_cara = this->getNormal(malla);
	Punto p1, p2, p3;
	Vect v1, v2, prod_cruz;
	double angulo;
	double angulo_max = 0;
	for(int i=0; i<num_elem; i++) {
		p1 = malla->getNodo(ind_nodos[i])->getPunto();
		p2 = malla->getNodo(ind_nodos[int(fmod(i+1,num_elem))])->getPunto();
		p3 = malla->getNodo(ind_nodos[int(fmod(i+2,num_elem))])->getPunto();
		Vect vp1(p1);
		Vect vp2(p2);
		Vect vp3(p3);
		v1 = vp1 - vp2;
		v2 = vp3 - vp2;
		prod_cruz = v1.prodCruz(v2);
		angulo = v1.getAngulo(v2);
		if(normal_cara.prodPunto(prod_cruz) > 0) {
			angulo = 2*PI - angulo;
		}
		if(angulo > angulo_max) {
			angulo_max = angulo;
		}
	}
	return angulo_max;
}
Пример #4
0
void RS_Image::mirror(const RS_Vector& axisPoint1, const RS_Vector& axisPoint2) {
    data.insertionPoint.mirror(axisPoint1, axisPoint2);
    RS_Vector vp0(0.,0.);
    RS_Vector vp1( axisPoint2-axisPoint1 );
    data.uVector.mirror(vp0,vp1);
    data.vVector.mirror(vp0,vp1);
    calculateBorders();
}
Пример #5
0
/**
 * find the closest grid point
 *@return the closest grid to given point
 *@coord: the given point
 */
RS_Vector RS_Grid::snapGrid(const RS_Vector& coord) const {
	if( cellV.x<RS_TOLERANCE || cellV.y<RS_TOLERANCE) return coord;
	RS_Vector vp(coord-baseGrid);
	if(isometric){
		//use remainder instead of fmod to locate the left-bottom corner for both positive and negative displacement
		RS_Vector vp1( vp-RS_Vector( remainder(vp.x-0.5*cellV.x,cellV.x)+0.5*cellV.x, remainder(vp.y-0.5*cellV.y,cellV.y)+0.5*cellV.y));
		RS_VectorSolutions sol({vp1,vp1+cellV,vp1+cellV*0.5, vp1+RS_Vector(cellV.x,0.), vp1+RS_Vector(0.,cellV.y)});
		vp1=sol.getClosest(vp);
		return baseGrid+vp1;

	}else{
		return baseGrid+vp-RS_Vector(remainder(vp.x,cellV.x),remainder(vp.y,cellV.y));
	}
}
Пример #6
0
RS_Vector RS_Circle::getNearestOrthTan(const RS_Vector& coord,
                    const RS_Line& normal,
                    bool /*onEntity = false*/)
{
        if ( !coord.valid) {
                return RS_Vector(false);
        }
        RS_Vector vp0(coord-getCenter());
        RS_Vector vp1(normal.getAngle1());
        double d=RS_Vector::dotP(vp0,vp1);
        if(d >= 0. ) {
                return getCenter() + vp1*getRadius();
        }else{
                return getCenter() - vp1*getRadius();
        }
}
Пример #7
0
/**
  * this function creates offset
  *@coord, position indicates the direction of offset
  *@distance, distance of offset
  * return true, if success, otherwise, false
  *
  *Author: Dongxu Li
  */
bool RS_Line::offset(const RS_Vector& coord, const double& distance) {
    RS_Vector direction(getEndpoint()-getStartpoint());
    double ds(direction.magnitude());
    if(ds< RS_TOLERANCE) return false;
    direction /= ds;
    RS_Vector vp(coord-getStartpoint());
    RS_Vector vp1(getStartpoint() + direction*(RS_Vector::dotP(direction,vp))); //projection
    direction.set(-direction.y,direction.x); //rotate pi/2
    if(RS_Vector::dotP(direction,vp)<0.) {
        direction *= -1.;
    }
    direction*=distance;
    move(direction);
    moveBorders(direction);
    return true;
}
Пример #8
0
Vect Cara::getNormal(Malla *malla) {
	assert(malla != 0);
	Punto p1,p2,p3;
	p1 = malla->getNodo(ind_nodos[0])->getPunto();
	p2 = malla->getNodo(ind_nodos[1])->getPunto();
	p3 = malla->getNodo(ind_nodos[2])->getPunto();
	Vect vp1(p1);
	Vect vp2(p2);
	Vect vp3(p3);
	Vect v12 = vp2 - vp1;
	Vect v13 = vp3 - vp2;
	Vect N = v12.prodCruz(v13);
	N.normalizar();

	return N;
}
Пример #9
0
/**
 * finds out which angles this dimension actually measures.
 *
 * @param ang1 Reference will return the start angle
 * @param ang2 Reference will return the end angle
 * @param reversed Reference will return the reversed flag.
 *
 * @return true: on success
 */
bool RS_DimAngular::getAngles(double& ang1, double& ang2, bool& reversed,
                              RS_Vector& p1, RS_Vector& p2) {

RS_Vector vp0(edata.definitionPoint4 - getCenter());
RS_Vector vp1(edata.definitionPoint2 - edata.definitionPoint1);
RS_Vector vp2(data.definitionPoint - edata.definitionPoint3);
// project p0 to the basis of p1 and p2
// p0 = a1 p1 + a2 p2
// <p0.p1>= a1 |p1|^2 + a2 <p1.p2>
// <p0,p2>= a1 <p1.p2> + a2 |p2|^2
// a1 = ( |p2|^2 <p0.p1> - <p1.p2><p0.p2>) /( |p1|^2 |p2|^2 - <p1.p2>^2)
// a2 = ( |p1|^2 <p0.p2> - <p1.p2><p0.p1>) /( |p1|^2 |p2|^2 - <p1.p2>^2)

double rp1=vp1.squared();
double rp2=vp2.squared();
double p0p1=RS_Vector::dotP(vp0,vp1);
double p0p2=RS_Vector::dotP(vp0,vp2);
double p1p2=RS_Vector::dotP(vp1,vp2);
double d= rp1*rp2 - p1p2*p1p2;
double a1=d*(rp2*p0p1-p1p2*p0p2); // we only need the sign, so, use multiply instead of division to avoid divid by zero;
if ( a1 >= 0. ) {
            p1 = edata.definitionPoint2;
} else {
            vp1 *= -1;
            p1 = edata.definitionPoint1;
}
a1 = d*(rp1*p0p2-p1p2*p0p1);
if ( a1 >= 0. ) {
            p2 = data.definitionPoint;
} else {
            vp2 *= -1;
            p2 = edata.definitionPoint3;
}

    RS_Vector center = getCenter();
    double ang = center.angleTo(edata.definitionPoint4);
ang1=vp1.angle();
ang2=vp2.angle();
if ( ! RS_Math::isAngleBetween(ang, ang1,ang2,false) ) {
reversed = true;
}
return true;
}
Пример #10
0
void DrawTContact(QPainter *p,pigalePaint *paint)
  {GeometricGraph G(paint->GCP);
  Prop<Tpoint> hp1(G.Set(tvertex()),PROP_DRAW_POINT_1);
  Prop<Tpoint> hp2(G.Set(tvertex()),PROP_DRAW_POINT_2);
  Prop<Tpoint> vp1(G.Set(tvertex()),PROP_DRAW_POINT_3);
  Prop<Tpoint> vp2(G.Set(tvertex()),PROP_DRAW_POINT_4);
  Prop<Tpoint> postxt(G.Set(tvertex()),PROP_DRAW_POINT_5);
  Prop1<double> sizetext(G.Set(),PROP_DRAW_DBLE_1);
  tvertex v;	
  // Draw horizontals and verticals
  for(v = 1;v <= G.nv();v++)
      {if(hp1[v].x() > .0)paint->DrawSeg(p,hp1[v],hp2[v],Black);
      if(vp1[v].x() > .0)paint->DrawSeg(p,vp1[v],vp2[v],Black);
      }
  // Draw text
  p->setFont(QFont("sans",Min((int)(sizetext() * Min(paint->xscale,paint->yscale) + .5),13)));
  for(v=1; v <= G.nv();v++)
      paint->DrawText(p,postxt[v],v,G.vcolor[v],0);
  }
Пример #11
0
/**
  *create circle inscribled in a triangle
  *
  *Author: Dongxu Li
  */
bool RS_Circle::createInscribe(const RS_Vector& coord, const std::vector<RS_Line*>& lines){
    if(lines.size()<3) return false;
	std::vector<RS_Line*> tri(lines);
    RS_VectorSolutions sol=RS_Information::getIntersectionLineLine(tri[0],tri[1]);
    if(sol.getNumber() == 0 ) {//move parallel to opposite
        std::swap(tri[1],tri[2]);
        sol=RS_Information::getIntersectionLineLine(tri[0],tri[1]);
    }
    if(sol.getNumber() == 0 ) return false;
    RS_Vector vp0(sol.get(0));
    sol=RS_Information::getIntersectionLineLine(tri[2],tri[1]);
    if(sol.getNumber() == 0 ) return false;
    RS_Vector vp1(sol.get(0));
    RS_Vector dvp(vp1-vp0);
    double a(dvp.squared());
    if( a< RS_TOLERANCE2) return false; //three lines share a common intersecting point
    RS_Vector vp(coord - vp0);
    vp -= dvp*(RS_Vector::dotP(dvp,vp)/a); //normal component
    RS_Vector vl0(tri[0]->getEndpoint() - tri[0]->getStartpoint());
    a=dvp.angle();
    double angle0(0.5*(vl0.angle() + a));
    if( RS_Vector::dotP(vp,vl0) <0.) {
        angle0 += 0.5*M_PI;
    }

    RS_Line line0(vp0, vp0+RS_Vector(angle0));//first bisecting line
    vl0=(tri[2]->getEndpoint() - tri[2]->getStartpoint());
    angle0=0.5*(vl0.angle() + a+M_PI);
    if( RS_Vector::dotP(vp,vl0) <0.) {
        angle0 += 0.5*M_PI;
    }
    RS_Line line1(vp1, vp1+RS_Vector(angle0));//second bisection line
    sol=RS_Information::getIntersectionLineLine(&line0,&line1);
    if(sol.getNumber() == 0 ) return false;

	bool ret=createFromCR(sol.get(0),tri[1]->getDistanceToPoint(sol.get(0)));
	if(!ret) return false;
	for(auto p: lines){
		if(! p->isTangent(data)) return false;
	}
	return true;
}
Пример #12
0
double Cara::getAnguloVertice(int ind_nodo, Malla *malla) {
	assert(malla != 0 && ind_nodo >= 0 && ind_nodo <= malla->getMaxIndiceNodos());
	Punto p1, p2, p3;
	Vect v1, v2;
	double angulo;
	for(int i=0; i<(int)ind_nodos.size(); i++) {
		// Buscamos que el nodo ind_nodo esté al medio
		if(ind_nodo != ind_nodos[int(fmod(i+1,ind_nodos.size()))])
			continue;
		p1 = malla->getNodo(ind_nodos[i])->getPunto();
		p2 = malla->getNodo(ind_nodos[int(fmod(i+1,num_elem))])->getPunto();
		p3 = malla->getNodo(ind_nodos[int(fmod(i+2,num_elem))])->getPunto();
		Vect vp1(p1);
		Vect vp2(p2);
		Vect vp3(p3);
		v1 = vp1 - vp2;
		v2 = vp3 - vp2;
		angulo = v1.getAngulo(v2);
		return angulo;
	}
	// el indice del nodo no pertenece a la cara
	assert(false);
	return 0;
}
Пример #13
0
/**
 * Draws the meta grid.
 *
 * @see drawIt()
 */
void RS_GraphicView::drawMetaGrid(RS_Painter *painter) {

	if (!(grid && isGridOn()) /*|| grid->getMetaSpacing()<0.0*/) {
		return;
	}

	//draw grid after metaGrid to avoid overwriting grid points by metaGrid lines
	//bug# 3430258
	grid->updatePointArray();
	RS_Pen pen(metaGridColor,
			   RS2::Width00,
			   RS2::DotLine);
	painter->setPen(pen);

	RS_Vector dv=grid->getMetaGridWidth().scale(factor);
	double dx=fabs(dv.x);
	double dy=fabs(dv.y); //potential bug, need to recover metaGrid.width
	// draw meta grid:
	auto mx = grid->getMetaX();
	for(auto const& x: mx){
		painter->drawLine(RS_Vector(toGuiX(x), 0),
						  RS_Vector(toGuiX(x), getHeight()));
		if(grid->isIsometric()){
			painter->drawLine(RS_Vector(toGuiX(x)+0.5*dx, 0),
							  RS_Vector(toGuiX(x)+0.5*dx, getHeight()));
		}
	}
	auto my = grid->getMetaY();
	if(grid->isIsometric()){//isometric metaGrid
		dx=fabs(dx);
		dy=fabs(dy);
		if(!my.size()|| dx<1||dy<1) return;
		RS_Vector baseMeta(toGui(RS_Vector(mx[0],my[0])));
		// x-x0=k*dx, x-remainder(x-x0,dx)
		RS_Vector vp0(-remainder(-baseMeta.x,dx)-dx,getHeight()-remainder(getHeight()-baseMeta.y,dy)+dy);
		RS_Vector vp1(vp0);
		RS_Vector vp2(getWidth()-remainder(getWidth()-baseMeta.x,dx)+dx,vp0.y);
		RS_Vector vp3(vp2);
		int cmx = round((vp2.x - vp0.x)/dx);
		int cmy = round((vp0.y +remainder(-baseMeta.y,dy)+dy)/dy);
		for(int i=cmx+cmy+2;i>=0;i--){
			if ( i <= cmx ) {
				vp0.x += dx;
				vp2.y -= dy;
			}else{
				vp0.y -= dy;
				vp2.x -= dx;
			}
			if ( i <= cmy ) {
				vp1.y -= dy;
				vp3.x -= dx;
			}else{
				vp1.x += dx;
				vp3.y -= dy;
			}
			painter->drawLine(vp0,vp1);
			painter->drawLine(vp2,vp3);
		}

	}else{//orthogonal

		for(auto const& y: my){
			painter->drawLine(RS_Vector(0, toGuiY(y)),
							  RS_Vector(getWidth(), toGuiY(y)));
		}
	}


}
Пример #14
0
void World::update(float timeStep)
{
    for(BodyList::iterator it = m_bodies.begin(); it != m_bodies.end(); ++it){
        if(!(*it)->getBodyDef().isStatic()){
            (*it)->acceleration(m_gravitation*timeStep);
            (*it)->update(timeStep);
        }
    }


    for(BodyList::iterator it = m_bodies.begin(); it != m_bodies.end(); ++it){
        BodyList::iterator ith = it;
        ith++;
        for(BodyList::iterator it2 = ith; it2 != m_bodies.end(); ++it2){
            if(!((*it)->getBodyDef().isStatic()) or !((*it2)->getBodyDef().isStatic())){
                if((*it)->getShape()->collide((*it2)->getShape().get())){
                    Polygon *p1 = static_cast<Polygon *>((*it)->getShape().get());
                    Polygon *p2 = static_cast<Polygon *>((*it2)->getShape().get());

                    bool b = true;
                    Line cl;

                    Vector2f point1 = p1->getTransformedPoint(p1->getNumberOfPoints()-1);
                    Vector2f point2 = p2->getTransformedPoint(p2->getNumberOfPoints()-1);

                    for(size_t i = 0; i < p1->getNumberOfPoints(); ++i){
                        Line line1(p1->getTransformedPoint(i), point1-p1->getTransformedPoint(i));
                        point1 = p1->getTransformedPoint(i);
                        for(size_t j = 0; j < p2->getNumberOfPoints(); ++j){
                            Line line2(p2->getTransformedPoint(j), point2-p2->getTransformedPoint(j));
                            point2 = p2->getTransformedPoint(j);

                            float t1 = line1.intersects(line2);
                            float t2 = line2.intersects(line1);

                            if(0.f < t1 and t1 < 1.f and 0.f < t2 and t2 < 1.f){
                                Vector2f vec = line1.getPoint() + t1 * line1.getDirectionVector();
                                if(b){
                                    cl.setPoint(vec);
                                    b = false;
                                } else {
                                    cl.setDirectionVector(vec - cl.getPoint());
                                }
                            }
                        }
                    }
                    Vector2f n = cl.getDirectionVector().normal();
                    //n.normalize();
                    Vector2f p = cl.getPoint()+(cl.getDirectionVector()/2.f);
                    Body::Ptr b1 = (*it);
                    Body::Ptr b2 = (*it2);

                    mx::Vector2f r1(p - b1->getShape()->getPosition());
                    mx::Vector2f r2(p - b2->getShape()->getPosition());

                    mx::Vector2f rap = r1.normal();
                    mx::Vector2f rbp = r2.normal();

                    float rapn = dot(rap, n);
                    float rbpn = dot(rbp, n);

                    mx::Vector2f vp1(b1->getVelocity()+b1->getAngularVelocity()*rap);
                    mx::Vector2f vp2(b2->getVelocity()+b2->getAngularVelocity()*rbp);
                    mx::Vector2f vab(vp2 - vp1);

                    float M1Inv = 0;
                    float M2Inv = 0;
                    float I1Inv = 0;
                    float I2Inv = 0;

                    if(!b1->getBodyDef().isStatic()){
                        M1Inv = 1.f / b1->getBodyDef().getMass();
                        I1Inv = 1.f / b1->getBodyDef().getMomentOfInertia();
                    }
                    if(!b2->getBodyDef().isStatic()){
                        M2Inv = 1.f / b2->getBodyDef().getMass();
                        I2Inv = 1.f / b2->getBodyDef().getMomentOfInertia();
                    }


                    float j = -(1+(b1->getBodyDef().getElasticity()+b2->getBodyDef().getElasticity())/2.f) * dot(vab, n);
                    j /= dot(n, n)*(M1Inv+M2Inv) + rapn*rapn*I1Inv + rbpn*rbpn*I2Inv;

                    b1->acceleration(-(j*M1Inv) * n);
                    b2->acceleration( (j*M2Inv) * n);

                    b1->angularAcceleration(-j*I1Inv * rapn);
                    b2->angularAcceleration( j*I2Inv * rbpn);

                    Shape::Ptr s1 = b1->getShape();
                    Shape::Ptr s2 = b2->getShape();

                    mx::Vector2f MTD = s1->MTD(s2.get());

                    float MInv = M1Inv + M2Inv;

                    s1->setPosition(s1->getPosition()+MTD*(M1Inv/MInv));
                    s2->setPosition(s2->getPosition()-MTD*(M2Inv/MInv));
                }
            }
        }
    }
}
bool fill_hole(std::vector<std::size_t> const & hole, UniGraph const & graph,
    mve::TriangleMesh::ConstPtr mesh, mve::MeshInfo const & mesh_info,
    std::vector<std::vector<VertexProjectionInfo> > * vertex_projection_infos,
    std::vector<TexturePatch::Ptr> * texture_patches) {

    mve::TriangleMesh::FaceList const & mesh_faces = mesh->get_faces();
    mve::TriangleMesh::VertexList const & vertices = mesh->get_vertices();

    std::map<std::size_t, std::set<std::size_t> > tmp;
    for (std::size_t const face_id : hole) {
        std::size_t const v0 = mesh_faces[face_id * 3];
        std::size_t const v1 = mesh_faces[face_id * 3 + 1];
        std::size_t const v2 = mesh_faces[face_id * 3 + 2];

        tmp[v0].insert(face_id);
        tmp[v1].insert(face_id);
        tmp[v2].insert(face_id);
    }

    std::size_t const num_vertices = tmp.size();
    /* Only fill small holes. */
    if (num_vertices > MAX_HOLE_NUM_FACES) return false;

    /* Calculate 2D parameterization using the technique from libremesh/patch2d,
     * which was published as sourcecode accompanying the following paper:
     *
     * Isotropic Surface Remeshing
     * Simon Fuhrmann, Jens Ackermann, Thomas Kalbe, Michael Goesele
     */

    std::size_t seed = -1;
    std::vector<bool> is_border(num_vertices, false);
    std::vector<std::vector<std::size_t> > adj_verts_via_border(num_vertices);
    /* Index structures to map from local <-> global vertex id. */
    std::map<std::size_t, std::size_t> g2l;
    std::vector<std::size_t> l2g(num_vertices);
    /* Index structure to determine column in matrix/vector. */
    std::vector<std::size_t> idx(num_vertices);

    std::size_t num_border_vertices = 0;

    bool disk_topology = true;
    std::map<std::size_t, std::set<std::size_t> >::iterator it = tmp.begin();
    for (std::size_t j = 0; j < num_vertices; ++j, ++it) {
        std::size_t vertex_id = it->first;
        g2l[vertex_id] = j;
        l2g[j] = vertex_id;

        /* Check topology in original mesh. */
        if (mesh_info[vertex_id].vclass != mve::MeshInfo::VERTEX_CLASS_SIMPLE) {
            /* Complex/Border vertex in original mesh */
            disk_topology = false;
            break;
        }

        /* Check new topology and determine if vertex is now at the border. */
        std::vector<std::size_t> const & adj_faces = mesh_info[vertex_id].faces;
        std::set<std::size_t> const & adj_hole_faces = it->second;
        std::vector<std::pair<std::size_t, std::size_t> > fan;
        for (std::size_t k = 0; k < adj_faces.size(); ++k) {
            std::size_t adj_face = adj_faces[k];
            if (graph.get_label(adj_faces[k]) == 0 &&
                adj_hole_faces.find(adj_face) != adj_hole_faces.end()) {
                std::size_t curr = adj_faces[k];
                std::size_t next = adj_faces[(k + 1) % adj_faces.size()];
                std::pair<std::size_t, std::size_t> pair(curr, next);
                fan.push_back(pair);
            }
        }

        std::size_t gaps = 0;
        for (std::size_t k = 0; k < fan.size(); k++) {
            std::size_t curr = fan[k].first;
            std::size_t next = fan[(k + 1) % fan.size()].first;
            if (fan[k].second != next) {
                ++gaps;

                for (std::size_t l = 0; l < 3; ++l) {
                    if(mesh_faces[curr * 3 + l] == vertex_id) {
                        std::size_t second = mesh_faces[curr * 3 + (l + 2) % 3];
                        adj_verts_via_border[j].push_back(second);
                    }
                    if(mesh_faces[next * 3 + l] == vertex_id) {
                        std::size_t first = mesh_faces[next * 3 + (l + 1) % 3];
                        adj_verts_via_border[j].push_back(first);
                    }
                }
            }
        }

        is_border[j] = gaps == 1;

        /* Check if vertex is now complex. */
        if (gaps > 1) {
            /* Complex vertex in hole */
            disk_topology = false;
            break;
        }

        if (is_border[j]) {
            idx[j] = num_border_vertices++;
            seed = vertex_id;
        } else {
            idx[j] = j - num_border_vertices;
        }
    }
    tmp.clear();

    /* No disk or genus zero topology */
    if (!disk_topology || num_border_vertices == 0) return false;

    std::vector<std::size_t> border; border.reserve(num_border_vertices);
    std::size_t prev = seed;
    std::size_t curr = seed;
    while (prev == seed || curr != seed) {
        std::size_t next = std::numeric_limits<std::size_t>::max();
        std::vector<std::size_t> const & adj_verts = adj_verts_via_border[g2l[curr]];
        for (std::size_t adj_vert : adj_verts) {
            assert(is_border[g2l[adj_vert]]);
            if (adj_vert != prev && adj_vert != curr) {
                next = adj_vert;
                break;
            }
        }
        if (next != std::numeric_limits<std::size_t>::max()) {
            prev = curr;
            curr = next;
            border.push_back(next);
        } else {
            /* No new border vertex */
            border.clear();
            break;
        }

        /* Loop within border */
        if (border.size() > num_border_vertices) break;
    }

    if (border.size() != num_border_vertices) return false;

    float total_length = 0.0f;
    float total_projection_length = 0.0f;
    for (std::size_t j = 0; j < border.size(); ++j) {
        std::size_t vi0 = border[j];
        std::size_t vi1 = border[(j + 1) % border.size()];
        std::vector<VertexProjectionInfo> const & vpi0 = vertex_projection_infos->at(vi0);
        std::vector<VertexProjectionInfo> const & vpi1 = vertex_projection_infos->at(vi0);
        /* According to the previous checks (vertex class within the origial
         * mesh and boundary) there already has to be at least one projection
         * of each border vertex. */
        assert(!vpi0.empty() && !vpi1.empty());
        math::Vec2f vp0(0.0f), vp1(0.0f);
        for (VertexProjectionInfo const & info0 : vpi0) {
            for (VertexProjectionInfo const & info1 : vpi1) {
                if (info0.texture_patch_id == info1.texture_patch_id) {
                    vp0 = info0.projection;
                    vp1 = info1.projection;
                    break;
                }
            }
        }
        total_projection_length += (vp0 - vp1).norm();
        math::Vec3f const & v0 = vertices[vi0];
        math::Vec3f const & v1 = vertices[vi1];
        total_length += (v0 - v1).norm();
    }
    float radius = total_projection_length / (2.0f * MATH_PI);

    if (total_length < std::numeric_limits<float>::epsilon()) return false;

    float length = 0.0f;
    std::vector<math::Vec2f> projections(num_vertices);
    for (std::size_t j = 0; j < border.size(); ++j) {
        float angle = 2.0f * MATH_PI * (length / total_length);
        projections[g2l[border[j]]] = math::Vec2f(std::cos(angle), std::sin(angle));
        math::Vec3f const & v0 = vertices[border[j]];
        math::Vec3f const & v1 = vertices[border[(j + 1) % border.size()]];
        length += (v0 - v1).norm();
    }

    typedef Eigen::Triplet<float, int> Triplet;
    std::vector<Triplet> coeff;
    std::size_t matrix_size = num_vertices - border.size();

    Eigen::VectorXf xx(matrix_size), xy(matrix_size);

    if (matrix_size != 0) {
        Eigen::VectorXf bx(matrix_size);
        Eigen::VectorXf by(matrix_size);
        for (std::size_t j = 0; j < num_vertices; ++j) {
            if (is_border[j]) continue;

            std::size_t const vertex_id = l2g[j];

            /* Calculate "Mean Value Coordinates" as proposed by Michael S. Floater */
            std::map<std::size_t, float> weights;
            std::vector<std::size_t> const & adj_faces = mesh_info[vertex_id].faces;
            for (std::size_t adj_face : adj_faces) {
                std::size_t v0 = mesh_faces[adj_face * 3];
                std::size_t v1 = mesh_faces[adj_face * 3 + 1];
                std::size_t v2 = mesh_faces[adj_face * 3 + 2];
                if (v1 == vertex_id) std::swap(v1, v0);
                if (v2 == vertex_id) std::swap(v2, v0);

                math::Vec3f v01 = vertices[v1] - vertices[v0];
                float v01n = v01.norm();
                math::Vec3f v02 = vertices[v2] - vertices[v0];
                float v02n = v02.norm();

                /* Ensure numerical stability */
                if (v01n * v02n < std::numeric_limits<float>::epsilon()) return false;

                float alpha = std::acos(v01.dot(v02) / (v01n * v02n));
                weights[g2l[v1]] += std::tan(alpha / 2.0f) / v01n;
                weights[g2l[v2]] += std::tan(alpha / 2.0f) / v02n;
            }

            std::map<std::size_t, float>::iterator it;
            float sum = 0.0f;
            for (it = weights.begin(); it != weights.end(); ++it)
                sum += it->second;
            assert(sum > 0.0f);
            for (it = weights.begin(); it != weights.end(); ++it)
                it->second /= sum;

            bx[idx[j]] = 0.0f;
            by[idx[j]] = 0.0f;
            for (it = weights.begin(); it != weights.end(); ++it) {
                if (is_border[it->first]) {
                    std::size_t border_vertex_id = border[idx[it->first]];
                    bx[idx[j]] += projections[g2l[border_vertex_id]][0] * it->second;
                    by[idx[j]] += projections[g2l[border_vertex_id]][1] * it->second;
                } else {
                    coeff.push_back(Triplet(idx[j], idx[it->first], -it->second));
                }
            }
        }

        for (std::size_t j = 0; j < matrix_size; ++j) {
            coeff.push_back(Triplet(j, j, 1.0f));
        }

        typedef Eigen::SparseMatrix<float> SpMat;
        SpMat A(matrix_size, matrix_size);
        A.setFromTriplets(coeff.begin(), coeff.end());

        Eigen::SparseLU<SpMat> solver;
        solver.analyzePattern(A);
        solver.factorize(A);
        xx = solver.solve(bx);
        xy = solver.solve(by);
    }

    float const max_hole_patch_size = MAX_HOLE_PATCH_SIZE;
    int image_size = std::min(std::floor(radius * 1.1f) * 2.0f, max_hole_patch_size);
    /* Ensure a minimum scale of one */
    image_size += 2 * (1 + texture_patch_border);
    int scale = image_size / 2 - texture_patch_border;
    for (std::size_t j = 0, k = 0; j < num_vertices; ++j) {
        if (is_border[j]) {
            projections[j] = projections[j] * scale + image_size / 2;
        } else {
            projections[j] = math::Vec2f(xx[k], xy[k]) * scale + image_size / 2;
            ++k;
        }
    }

    mve::ByteImage::Ptr image = mve::ByteImage::create(image_size, image_size, 3);
    //DEBUG image->fill_color(*math::Vec4uc(0, 255, 0, 255));
    std::vector<math::Vec2f> texcoords; texcoords.reserve(hole.size());
    for (std::size_t const face_id : hole) {
        for (std::size_t j = 0; j < 3; ++j) {
            std::size_t const vertex_id = mesh_faces[face_id * 3 + j];
            math::Vec2f const & projection = projections[g2l[vertex_id]];
            texcoords.push_back(projection);
        }
    }
    TexturePatch::Ptr texture_patch = TexturePatch::create(0, hole, texcoords, image);
    std::size_t texture_patch_id;
    #pragma omp critical
    {
        texture_patches->push_back(texture_patch);
        texture_patch_id = texture_patches->size() - 1;
    }

    for (std::size_t j = 0; j < num_vertices; ++j) {
        std::size_t const vertex_id = l2g[j];
        std::vector<std::size_t> const & adj_faces = mesh_info[vertex_id].faces;
        std::vector<std::size_t> faces; faces.reserve(adj_faces.size());
        for (std::size_t adj_face : adj_faces) {
            if (graph.get_label(adj_face) == 0) {
                faces.push_back(adj_face);
            }
        }
        VertexProjectionInfo info = {texture_patch_id, projections[j], faces};
        #pragma omp critical
        vertex_projection_infos->at(vertex_id).push_back(info);
    }

    return true;
}
void
generate_texture_patches(UniGraph const & graph, std::vector<TextureView> const & texture_views,
    mve::TriangleMesh::ConstPtr mesh, mve::VertexInfoList::ConstPtr vertex_infos,
    std::vector<std::vector<VertexProjectionInfo> > * vertex_projection_infos,
    std::vector<TexturePatch> * texture_patches) {

    util::WallTimer timer;

    mve::TriangleMesh::FaceList const & mesh_faces = mesh->get_faces();
    mve::TriangleMesh::VertexList const & vertices = mesh->get_vertices();
    vertex_projection_infos->resize(vertices.size());

    std::size_t num_patches = 0;

    std::cout << "\tRunning... " << std::flush;
    #pragma omp parallel for schedule(dynamic)
    for (std::size_t i = 0; i < texture_views.size(); ++i) {

        std::vector<std::vector<std::size_t> > subgraphs;
        int const label = i + 1;
        graph.get_subgraphs(label, &subgraphs);

        std::list<TexturePatchCandidate> candidates;
        for (std::size_t j = 0; j < subgraphs.size(); ++j) {
            candidates.push_back(generate_candidate(label, texture_views[i], subgraphs[j], mesh));
        }

        /* Merge candidates which contain the same image content. */
        std::list<TexturePatchCandidate>::iterator it, sit;
        for (it = candidates.begin(); it != candidates.end(); ++it) {
            for (sit = candidates.begin(); sit != candidates.end();) {
                Rect<int> bounding_box = sit->bounding_box;
                if (it != sit && bounding_box.is_inside(&it->bounding_box)) {
                    TexturePatch::Faces & faces = it->texture_patch.get_faces();
                    TexturePatch::Faces & ofaces = sit->texture_patch.get_faces();
                    faces.insert(faces.end(), ofaces.begin(), ofaces.end());

                    TexturePatch::Texcoords & texcoords = it->texture_patch.get_texcoords();
                    TexturePatch::Texcoords & otexcoords = sit->texture_patch.get_texcoords();
                    math::Vec2f offset;
                    offset[0] = sit->bounding_box.min_x - it->bounding_box.min_x;
                    offset[1] = sit->bounding_box.min_y - it->bounding_box.min_y;
                    for (std::size_t i = 0; i < otexcoords.size(); ++i) {
                        texcoords.push_back(otexcoords[i] + offset);
                    }

                    sit = candidates.erase(sit);
                } else {
                    ++sit;
                }
            }
        }

        it = candidates.begin();
        for (; it != candidates.end(); ++it) {
            std::size_t texture_patch_id;

            #pragma omp critical
            {
                texture_patches->push_back(it->texture_patch);
                texture_patch_id = num_patches++;
            }

            std::vector<std::size_t> const & faces = it->texture_patch.get_faces();
            std::vector<math::Vec2f> const & texcoords = it->texture_patch.get_texcoords();
            for (std::size_t i = 0; i < faces.size(); ++i) {
                std::size_t const face_id = faces[i];
                std::size_t const face_pos = face_id * 3;
                for (std::size_t j = 0; j < 3; ++j) {
                    std::size_t const vertex_id = mesh_faces[face_pos  + j];
                    math::Vec2f const projection = texcoords[i * 3 + j];

                    VertexProjectionInfo info = {texture_patch_id, projection, {face_id}};

                    #pragma omp critical
                    vertex_projection_infos->at(vertex_id).push_back(info);
                }
            }
        }
    }

    merge_vertex_projection_infos(vertex_projection_infos);

    std::size_t num_holes = 0;
    std::size_t num_hole_faces = 0;

    //if (!settings.skip_hole_filling) {
    {
        std::vector<std::vector<std::size_t> > subgraphs;
        graph.get_subgraphs(0, &subgraphs);

        #pragma omp parallel for schedule(dynamic)
        for (std::size_t i = 0; i < subgraphs.size(); ++i) {
            std::vector<std::size_t> const & subgraph = subgraphs[i];

            std::map<std::size_t, std::set<std::size_t> > tmp;
            for (std::size_t const face_id : subgraph) {
                std::size_t const v0 = mesh_faces[face_id * 3];
                std::size_t const v1 = mesh_faces[face_id * 3 + 1];
                std::size_t const v2 = mesh_faces[face_id * 3 + 2];
                tmp[v0].insert(face_id);
                tmp[v1].insert(face_id);
                tmp[v2].insert(face_id);
            }

            std::size_t const num_vertices = tmp.size();
            /* Only fill small holes. */
            if (num_vertices > 100) {
                //std::cerr << "Hole to large" << std::endl;
                continue;
            }


            /* Calculate 2D parameterization using the technique from libremesh/patch2d,
             * which was published as sourcecode accompanying the following paper:
             *
             * Isotropic Surface Remeshing
             * Simon Fuhrmann, Jens Ackermann, Thomas Kalbe, Michael Goesele
             */

            std::size_t seed = -1;
            std::vector<bool> is_border(num_vertices, false);
            std::vector<std::vector<std::size_t> > adj_verts_via_border(num_vertices);
            /* Index structures to map from local <-> global vertex id. */
            std::map<std::size_t, std::size_t> g2l;
            std::vector<std::size_t> l2g(num_vertices);
            /* Index structure to determine column in matrix/vector. */
            std::vector<std::size_t> idx(num_vertices);

            std::size_t num_border_vertices = 0;

            bool disk_topology = true;
            std::map<std::size_t, std::set<std::size_t> >::iterator it = tmp.begin();
            for (std::size_t j = 0; j < num_vertices; ++j, ++it) {
                std::size_t vertex_id = it->first;
                g2l[vertex_id] = j;
                l2g[j] = vertex_id;

                /* Check topology in original mesh. */
                if (vertex_infos->at(vertex_id).vclass != mve::VERTEX_CLASS_SIMPLE) {
                    //std::cerr << "Complex/Border vertex in original mesh" << std::endl;
                    disk_topology = false;
                    break;
                }

                /* Check new topology and determine if vertex is now at the border. */
                std::vector<std::size_t> const & adj_faces = vertex_infos->at(vertex_id).faces;
                std::set<std::size_t> const & adj_hole_faces = it->second;
                std::vector<std::pair<std::size_t, std::size_t> > fan;
                for (std::size_t k = 0; k < adj_faces.size(); ++k) {
                    std::size_t adj_face = adj_faces[k];
                    if (graph.get_label(adj_faces[k]) == 0 &&
                        adj_hole_faces.find(adj_face) != adj_hole_faces.end()) {
                        std::size_t curr = adj_faces[k];
                        std::size_t next = adj_faces[(k + 1) % adj_faces.size()];
                        std::pair<std::size_t, std::size_t> pair(curr, next);
                        fan.push_back(pair);
                    }
                }

                std::size_t gaps = 0;
                for (std::size_t k = 0; k < fan.size(); k++) {
                    std::size_t curr = fan[k].first;
                    std::size_t next = fan[(k + 1) % fan.size()].first;
                    if (fan[k].second != next) {
                        ++gaps;

                        for (std::size_t l = 0; l < 3; ++l) {
                            if(mesh_faces[curr * 3 + l] == vertex_id) {
                                std::size_t second = mesh_faces[curr * 3 + (l + 2) % 3];
                                adj_verts_via_border[j].push_back(second);
                            }
                            if(mesh_faces[next * 3 + l] == vertex_id) {
                                std::size_t first = mesh_faces[next * 3 + (l + 1) % 3];
                                adj_verts_via_border[j].push_back(first);
                            }
                        }
                    }
                }

                is_border[j] = gaps == 1;

                /* Check if vertex is now complex. */
                if (gaps > 1) {
                    //std::cerr << "Complex vertex in hole" << std::endl;
                    disk_topology = false;
                    break;
                }

                if (is_border[j]) {
                    idx[j] = num_border_vertices++;
                    seed = vertex_id;
                } else {
                    idx[j] = j - num_border_vertices;
                }
            }
            tmp.clear();

            if (!disk_topology) continue;
            if (num_border_vertices == 0) {
                //std::cerr << "Genus zero topology" << std::endl;
                continue;
            }

            std::vector<std::size_t> border; border.reserve(num_border_vertices);
            std::size_t prev = seed;
            std::size_t curr = seed;
            while (prev == seed || curr != seed) {
                std::size_t next = std::numeric_limits<std::size_t>::max();
                std::vector<std::size_t> const & adj_verts = adj_verts_via_border[g2l[curr]];
                for (std::size_t adj_vert : adj_verts) {
                    assert(is_border[g2l[adj_vert]]);
                    if (adj_vert != prev && adj_vert != curr) {
                        next = adj_vert;
                        break;
                    }
                }
                if (next != std::numeric_limits<std::size_t>::max()) {
                    prev = curr;
                    curr = next;
                    border.push_back(next);
                } else {
                    //std::cerr << "No new border vertex" << std::endl;
                    border.clear();
                    break;
                }

                if (border.size() > num_border_vertices) {
                    //std::cerr << "Loop within border" << std::endl;
                    break;
                }
            }

            if (border.size() != num_border_vertices) {
                continue;
            }

            float total_length = 0.0f;
            float total_projection_length = 0.0f;
            for (std::size_t j = 0; j < border.size(); ++j) {
                std::size_t vi0 = border[j];
                std::size_t vi1 = border[(j + 1) % border.size()];
                std::vector<VertexProjectionInfo> const & vpi0 = vertex_projection_infos->at(vi0);
                std::vector<VertexProjectionInfo> const & vpi1 = vertex_projection_infos->at(vi0);
                /* According to the previous checks (vertex class within the origial
                 * mesh and boundary) there already has to be at least one projection
                 * of each border vertex. */
                assert(!vpi0.empty() && !vpi1.empty());
                math::Vec2f vp0(0.0f), vp1(0.0f);
                for (VertexProjectionInfo const & info0 : vpi0) {
                    for (VertexProjectionInfo const & info1 : vpi1) {
                        if (info0.texture_patch_id == info1.texture_patch_id) {
                            vp0 = info0.projection;
                            vp1 = info1.projection;
                            break;
                        }
                    }
                }
                total_projection_length += (vp0 - vp1).norm();
                math::Vec3f const & v0 = vertices[vi0];
                math::Vec3f const & v1 = vertices[vi1];
                total_length += (v0 - v1).norm();
            }
            float radius = total_projection_length / (2.0f * MATH_PI);

            float length = 0.0f;
            std::vector<math::Vec2f> projections(num_vertices);
            for (std::size_t j = 0; j < border.size(); ++j) {
                float angle = 2.0f * MATH_PI * (length / total_length);
                projections[g2l[border[j]]] = math::Vec2f(std::cos(angle), std::sin(angle));
                math::Vec3f const & v0 = vertices[border[j]];
                math::Vec3f const & v1 = vertices[border[(j + 1) % border.size()]];
                length += (v0 - v1).norm();
            }

            typedef Eigen::Triplet<float, int> Triplet;
            std::vector<Triplet> coeff;
            std::size_t matrix_size = num_vertices - border.size();

            Eigen::VectorXf xx(matrix_size), xy(matrix_size);

            if (matrix_size != 0) {
                Eigen::VectorXf bx(matrix_size);
                Eigen::VectorXf by(matrix_size);
                for (std::size_t j = 0; j < num_vertices; ++j) {
                    if (is_border[j]) continue;

                    std::size_t const vertex_id = l2g[j];

                    /* Calculate "Mean Value Coordinates" as proposed by Michael S. Floater */
                    std::map<std::size_t, float> weights;
                    std::vector<std::size_t> const & adj_faces = vertex_infos->at(vertex_id).faces;
                    for (std::size_t adj_face : adj_faces) {
                        std::size_t v0 = mesh_faces[adj_face * 3];
                        std::size_t v1 = mesh_faces[adj_face * 3 + 1];
                        std::size_t v2 = mesh_faces[adj_face * 3 + 2];
                        if (v1 == vertex_id) std::swap(v1, v0);
                        if (v2 == vertex_id) std::swap(v2, v0);

                        math::Vec3f v01 = vertices[v1] - vertices[v0];
                        float v01n = v01.norm();
                        math::Vec3f v02 = vertices[v2] - vertices[v0];
                        float v02n = v02.norm();
                        float alpha = std::acos(v01.dot(v02) / (v01n * v02n));
                        weights[g2l[v1]] += std::tan(alpha / 2.0f) / v01n;
                        weights[g2l[v2]] += std::tan(alpha / 2.0f) / v02n;
                    }

                    std::map<std::size_t, float>::iterator it;
                    float sum = 0.0f;
                    for (it = weights.begin(); it != weights.end(); ++it)
                        sum += it->second;
                    for (it = weights.begin(); it != weights.end(); ++it)
                        it->second /= sum;

                    bx[idx[j]] = 0.0f;
                    by[idx[j]] = 0.0f;
                    for (it = weights.begin(); it != weights.end(); ++it) {
                        if (is_border[it->first]) {
                            std::size_t border_vertex_id = border[idx[it->first]];
                            bx[idx[j]] += projections[g2l[border_vertex_id]][0] * it->second;
                            by[idx[j]] += projections[g2l[border_vertex_id]][1] * it->second;
                        } else {
                            coeff.push_back(Triplet(idx[j], idx[it->first], -it->second));
                        }
                    }
                }
                for (std::size_t j = 0; j < matrix_size; ++j) {
                    coeff.push_back(Triplet(j, j, 1.0f));
                }

                typedef Eigen::SparseMatrix<float> SpMat;
                SpMat A(matrix_size, matrix_size);
                A.setFromTriplets(coeff.begin(), coeff.end());

                Eigen::SparseLU<SpMat> solver;
                solver.analyzePattern(A);
                solver.factorize(A);
                xx = solver.solve(bx);
                xy = solver.solve(by);
            }

            int image_size = std::floor(radius * 1.1f) * 2 + 4;
            int scale = image_size / 2 - texture_patch_border;
            for (std::size_t j = 0, k = 0; j < num_vertices; ++j) {
                if (!is_border[j]) {
                    projections[j] = math::Vec2f(xx[k], xy[k]) * scale + image_size / 2;
                    ++k;
                } else {
                    projections[j] = projections[j] * scale + image_size / 2;
                }
            }

            mve::ByteImage::Ptr image = mve::ByteImage::create(image_size, image_size, 3);
            //DEBUG image->fill_color(*math::Vec4uc(0, 255, 0, 255));
            std::vector<math::Vec2f> texcoords; texcoords.reserve(subgraph.size());
            for (std::size_t const face_id : subgraph) {
                for (std::size_t j = 0; j < 3; ++j) {
                    std::size_t const vertex_id = mesh_faces[face_id * 3 + j];
                    math::Vec2f const & projection = projections[g2l[vertex_id]];
                    texcoords.push_back(projection);
                }
            }
            TexturePatch texture_patch(0, subgraph, texcoords, image);
            std::size_t texture_patch_id;
            #pragma omp critical
            {
                texture_patches->push_back(texture_patch);
                texture_patch_id = num_patches++;

                num_hole_faces += subgraph.size();
                ++num_holes;
            }

            for (std::size_t j = 0; j < num_vertices; ++j) {
                std::size_t const vertex_id = l2g[j];
                std::vector<std::size_t> const & adj_faces = vertex_infos->at(vertex_id).faces;
                std::vector<std::size_t> faces; faces.reserve(adj_faces.size());
                for (std::size_t adj_face : adj_faces) {
                    if (graph.get_label(adj_face) == 0) {
                        faces.push_back(adj_face);
                    }
                }
                VertexProjectionInfo info = {texture_patch_id, projections[j], faces};
                #pragma omp critical
                vertex_projection_infos->at(vertex_id).push_back(info);
            }
        }
    }

    merge_vertex_projection_infos(vertex_projection_infos);

    std::cout << "done. (Took " << timer.get_elapsed_sec() << "s)" << std::endl;
    std::cout << "\t" << num_patches << " texture patches." << std::endl;
    std::cout << "\t" << num_holes << " holes (" << num_hole_faces << " faces)." << std::endl;
}