#include <Layout.h>
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 | |
Mesh * | mesh |
std::stack< Edge * > | edgesToFacesTodo |
Stack of edges that point to the faces that might need to be layout. |
|
Only sets mesh pointer to current mesh.
Definition at line 17 of file Layout.cpp. 00017 { 00018 mesh = _mesh; 00019 }
|
|
Definition at line 273 of file Layout.cpp.
|
|
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: Where for the internal edges , and for the boundary edges . 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 }
|
|
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 }
|
|
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 }
|
|
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 }
|
|
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 }
|
|
Stack of edges that point to the faces that might need to be layout.
|
|
|