Layout Class Reference

#include <Layout.h>

List of all members.


Detailed Description

Class that assigns UV coordinates for mesh vertices.

If no cone singularities are used no extra information is required for the layout.

If cone singularities are used, then cuts need to be defined. The cuts need to be defined in such a way that when mesh is cut, each patch is a disk with single boundary loop and each cone singularity is at the boundary of at least one patch.

The user is responsible for providing valid cuts via -ie option.

Definition at line 21 of file Layout.h.

Public Member Functions

 Layout (Mesh *_mesh)
 Only sets mesh pointer to current mesh.
void computeEdgeLengthAndAngles ()
 Computes edge lengths in the final parameterization.
void layoutMesh ()
 This function assigns UV coordinates based on the information returned from circle pattern optimization.
void movePatches ()
 Moves the patches in the UV plane so that they do not overlap when the mesh is cut into separate components.
bool validCuts ()
 Checks if the cuts given are valid cuts.
 ~Layout (void)

Private Member Functions

void putFaceFrom (Edge *e)
 Given an edge with UV coordinates assigned for the beginning and end vertices of the edge, this function puts the third vertex of the face that it belongs two.

Private Attributes

Meshmesh
std::stack< Edge * > edgesToFacesTodo
 Stack of edges that point to the faces that might need to be layout.


Constructor & Destructor Documentation

Layout::Layout Mesh _mesh  ) 
 

Only sets mesh pointer to current mesh.

Definition at line 17 of file Layout.cpp.

00017                            {
00018    mesh = _mesh;
00019 }

Layout::~Layout void   ) 
 

Definition at line 273 of file Layout.cpp.

00273                     {
00274 }


Member Function Documentation

void Layout::computeEdgeLengthAndAngles  ) 
 

Computes edge lengths in the final parameterization.

When radii of circumcircles (r) and intersection angles (theta) are known, final edge length for an edge e can be computed as: $l_e = 2 r_1 \sin(\varphi_e)$

Where for the internal edges $\varphi_e=\textrm{ atan2 }(\sin\theta_e, e^{r_2-r_1} - \cos\theta_e)=\frac{\pi}{2}-\textrm{ atan2 }(1-e^{r_2-r_1}\cos\theta, e^{r_2-r_1}\sin\theta)$ , and for the boundary edges $\varphi_e=\pi - \theta_e$ .

$\varphi_e$ is also alphaOposite angle associated with edge e.

This function needs to be called before layoutMesh function.

Definition at line 95 of file Layout.cpp.

00095                                         {
00096    Mesh::HalfEdgeIterator eIter = mesh->halfEdgeIterator();
00097    for (; !eIter.end(); eIter++) {
00098       Edge * e = eIter.half_edge();
00099       double r;
00100       double phi;
00101       double r2 = -1;
00102       if (!e->isBoundary()) {
00103           r = e->face->r;
00104           r2 = e->pair->face->r;
00105           phi = 0.5*CirclePattern::fTheta2(e->cosTheta(), e->sinTheta(), log(r2) - log(r));
00106 
00107       }
00108       else {
00109           if (!e->face)
00110              e = e->pair;
00111 
00112           r = e->face->r;
00113           phi = M_PI - e->theta();
00114       }
00115 
00116       e->length = 2.0*r*sin(phi);
00117       e->alphaOposite = phi;
00118       if (!e->pair->face) {
00119           e->pair->length = e->length;
00120           e->pair->alphaOposite = 0;
00121       }
00122    }
00123 }

void Layout::layoutMesh  ) 
 

This function assigns UV coordinates based on the information returned from circle pattern optimization.

If the mesh is closed, or has genus more then 0, cone singularities and cuts need to be given.

Definition at line 126 of file Layout.cpp.

00126                         {
00127 
00128    Mesh::FaceIterator fIter = mesh->faceIterator();
00129    for (; !fIter.end(); fIter++) {
00130       fIter.face()->check = false;
00131    }
00132 
00133    Mesh::VertexIterator vIter = mesh->vertexIterator();
00134    for (; !vIter.end(); vIter++) {
00135       vIter.vertex()->uv = Vector3(0,0,0);
00136       vIter.vertex()->check = false;
00137    }
00138 
00139    for (fIter.reset(); !fIter.end(); fIter++) {
00140       if (!fIter.face()->check) {
00141           Edge * e = fIter.face()->edge;
00142           e->vertex->uv = Vector3(0,0,-2);
00143           e->next->vertex->uv = Vector3(e->length,0,0);
00144           e->vertex->check = true;
00145           e->next->vertex->check = true;
00146           edgesToFacesTodo.push(e);
00147           while (!edgesToFacesTodo.empty()) {
00148              Edge * toDo = edgesToFacesTodo.top();
00149              edgesToFacesTodo.pop();
00150              putFaceFrom(toDo);
00151           }
00152       }
00153    }
00154 
00155    if (mesh->numConnectedComponents > 1)
00156       movePatches();
00157 }

void Layout::movePatches  ) 
 

Moves the patches in the UV plane so that they do not overlap when the mesh is cut into separate components.

The patches are not packed though in some intelligent way, they are just shifted form each other in x and y direction to approximately cover a square.

More sophisticated packing could be done as a post processing step.

Definition at line 198 of file Layout.cpp.

00198                          {
00199    if (mesh->numConnectedComponents == 1)
00200       return;
00201 
00202    /* Compute bounding box for each patch and shift them away from each other */
00203    Vector3 * lowLeftCorner = new Vector3[mesh->numConnectedComponents];
00204    Vector3 * upRightCorner = new Vector3[mesh->numConnectedComponents];
00205    bool * started = new bool[mesh->numConnectedComponents];
00206    for (int i = 0; i < mesh->numConnectedComponents; i++)
00207       started[i] = false;
00208 
00209    int patchID;
00210    Vector3 uv;
00211    Mesh::VertexIterator vIter = mesh->vertexIterator();
00212    for (vIter.reset(); !vIter.end(); vIter++) {
00213       patchID = vIter.vertex()->patchID;
00214       uv = vIter.vertex()->uv;
00215       if (!started[patchID]) {
00216           started[patchID] = true;
00217           lowLeftCorner[patchID] = uv;
00218           upRightCorner[patchID] = uv;
00219       }
00220       else {
00221           if (lowLeftCorner[patchID].x() > uv.x())
00222              lowLeftCorner[patchID].x() = uv.x();
00223           if (lowLeftCorner[patchID].y() > uv.y())
00224              lowLeftCorner[patchID].y() = uv.y();
00225           if (upRightCorner[patchID].x() < uv.x())
00226              upRightCorner[patchID].x() = uv.x();
00227           if (upRightCorner[patchID].y() < uv.y())
00228              upRightCorner[patchID].y() = uv.y();
00229       }
00230    }
00231 
00232    /* Translate all the patches so that the low left coner of each of them is at (0,0) */
00233    for (vIter.reset(); !vIter.end(); vIter++)
00234       vIter.vertex()->uv -= lowLeftCorner[vIter.vertex()->patchID];
00235 
00236 
00237    double maxX = upRightCorner[0].x() - lowLeftCorner[0].x(), 
00238       maxY = upRightCorner[0].y() - lowLeftCorner[0].y();
00239 
00240    for (int i = 1; i < mesh->numConnectedComponents; i++) {
00241       if ((upRightCorner[i].x() - lowLeftCorner[i].x()) > maxX)
00242           maxX = upRightCorner[i].x() - lowLeftCorner[i].x();
00243       if ((upRightCorner[i].y() - lowLeftCorner[i].y()) > maxY)
00244           maxY = upRightCorner[i].y() - lowLeftCorner[i].y();
00245    }
00246    delete [] lowLeftCorner;
00247    delete [] upRightCorner;
00248    delete [] started;
00249 
00250    int boxDim = (int)ceil(sqrt((double)mesh->numConnectedComponents));
00251    Vector3 * shiftPos = new Vector3[mesh->numConnectedComponents];
00252    for (int i = 0; i < boxDim; i++) {
00253       for (int j = 0; j < boxDim; j++) {
00254           patchID = i*boxDim + j;
00255           if (patchID < mesh->numConnectedComponents) {
00256              shiftPos[patchID].x() = maxX*(double)i;
00257              shiftPos[patchID].y() = maxY*(double)j;
00258           }
00259       }
00260    }
00261 
00262    /* Translate all the patches so that the low left coner of each of 
00263    them is at the correct grid position */
00264    for (vIter.reset(); !vIter.end(); vIter++)
00265       vIter.vertex()->uv += shiftPos[vIter.vertex()->patchID];
00266 
00267    delete [] shiftPos;
00268 }

void Layout::putFaceFrom Edge e  )  [private]
 

Given an edge with UV coordinates assigned for the beginning and end vertices of the edge, this function puts the third vertex of the face that it belongs two.

Get vector that existing edge on the plane forms

Normalize it

Rotate over alpha oposite to previous edge

Put the vertex of the previous edge (vertex that is oposite to current edge)

Definition at line 159 of file Layout.cpp.

00159                                  {
00160    if (e->face->check) return;
00161    Edge * prev = e->next->next;
00162  //  if (!prev->vertex->check) {
00164       Vector3 oposite = e->vertex->uv - e->next->vertex->uv;
00166       oposite.normalize();
00168       Vector3 res;
00169       Vector3 start;
00170       double angle, length;
00171       if (fabs(0.5*M_PI - prev->alphaOposite) < fabs(0.5*M_PI - e->next->alphaOposite)) {
00172           angle = prev->alphaOposite;
00173           length = e->next->length;
00174           start = e->next->vertex->uv;
00175       }
00176       else {
00177           angle = -e->next->alphaOposite;
00178           length = prev->length;
00179           oposite.negate();
00180           start = e->vertex->uv;
00181       }
00182 
00183       res[0] =   cos(angle)*oposite[0] + sin(angle)*oposite[1];
00184       res[1] =  -sin(angle)*oposite[0] + cos(angle)*oposite[1];
00185 
00187       prev->vertex->uv = start + res*length;
00188       prev->vertex->check = true;
00189   // }
00190    Face::EdgeAroundIterator iter = e->face->iterator();
00191    for( ; !iter.end(); iter++) {
00192       if (iter.face() && !iter.face()->check)
00193           edgesToFacesTodo.push(iter.edge()->pair);
00194    }
00195    e->face->check = true;
00196 }

bool Layout::validCuts  ) 
 

Checks if the cuts given are valid cuts.

When this function is called, the mesh is already cut.

First check that each patch is topologically a disk, which means that for each patch the formula: V - E + F = 1 holds. Next, check that every cone singularity vertex is on the boundary of the patch.

Definition at line 23 of file Layout.cpp.

00023                        {
00024 
00025    bool result = true;
00026 
00027    // Number of connected components
00028    int numConnectedComponents = 0;
00029    Mesh::FaceIterator fIter = mesh->faceIterator();
00030    for (; !fIter.end(); fIter++) {
00031       fIter.face()->check = false;
00032    }
00033    stack<Edge *> toVisit;
00034    for (fIter.reset(); !fIter.end(); fIter++) {
00035       if (!fIter.face()->check) {
00036           numConnectedComponents++;
00037           toVisit.push(fIter.face()->edge);
00038           while (!toVisit.empty()) {
00039              Face * fIn = toVisit.top()->face; 
00040              toVisit.pop();
00041              fIn->check = true;     
00042              fIn->patchID = numConnectedComponents-1;
00043              Face::EdgeAroundIterator iter = fIn->iterator();
00044              for (; !iter.end(); iter++) {
00045                 iter.edge()->patchID       = numConnectedComponents-1;
00046                 iter.edge()->pair->patchID = numConnectedComponents-1;
00047                 iter.vertex()->patchID     = numConnectedComponents-1;
00048                 if (iter.edge()->pair->face && !iter.edge()->pair->face->check)
00049                     toVisit.push(iter.edge()->pair);
00050              }
00051           }
00052       }
00053    }
00054 
00055    double * eulerNums = new double[numConnectedComponents+1];
00056    int i;
00057    for (i = 0; i < numConnectedComponents; i++)
00058       eulerNums[i] = 0;
00059 
00060    Mesh::VertexIterator vIter = mesh->vertexIterator();
00061    for (; !vIter.end(); vIter++)
00062       eulerNums[vIter.vertex()->patchID] += 1;
00063    for (fIter.reset(); !fIter.end(); fIter++)
00064       eulerNums[fIter.face()->patchID] += 1;
00065    Mesh::EdgeIterator eIter = mesh->edgeIterator();
00066    for (; !eIter.end(); eIter++) {
00067       eulerNums[eIter.edge()->patchID] -= 1;
00068    }
00069 
00070    for (i = 0; i < numConnectedComponents; i++) {
00071       cout << "Euler number of patch " << (i+1) << ": " << eulerNums[i] << endl;
00072       check_warn(eulerNums[i] != 1, 
00073           "Patch is not developable!\nMost probably the result layout will not be correct.");
00074       result = false;
00075    }
00076 
00077    delete [] eulerNums;
00078 
00079    for (vIter.reset(); !vIter.end(); vIter++) {
00080       if (vIter.vertex()->constrained) {
00081           check_warn(!vIter.vertex()->isBoundary(), 
00082              "Cone singularity vertex is not on the boundary!\nMost probably the result layout will not be correct.");
00083           result = false;
00084       }
00085    }
00086 
00087    cout << "------------------------------------" << endl;
00088    cout << "After cutting: ";
00089    mesh->computeMeshInfo();
00090    cout << "------------------------------------" << endl;
00091 
00092    return result;
00093 }


Member Data Documentation

std::stack<Edge *> Layout::edgesToFacesTodo [private]
 

Stack of edges that point to the faces that might need to be layout.

Definition at line 28 of file Layout.h.

Mesh* Layout::mesh [private]
 

Definition at line 24 of file Layout.h.


The documentation for this class was generated from the following files:
Generated on Sat Jun 3 13:33:43 2006 for CirclePatterns by  doxygen 1.4.5