MeshKit
1.0
|
00001 #include "meshkit/AF2Rule.hpp" 00002 00003 // C++ 00004 #include <set> 00005 #include <stack> 00006 00007 // MeshKit 00008 #include "meshkit/AF2Binding.hpp" 00009 #include "meshkit/AF2RuleApplication.hpp" 00010 #include "meshkit/Error.hpp" 00011 using namespace MeshKit; 00016 template<class T> 00017 void aF2RuleCopyListToArray(std::list<T*> const & aListOfPtr, 00018 T** & anArrayOfPtr, unsigned int offset = 0u) 00019 { 00020 anArrayOfPtr = new T*[offset + aListOfPtr.size()]; 00021 typedef typename std::list<T*>::const_iterator ItrType; 00022 unsigned int indx = offset; 00023 for (ItrType itr = aListOfPtr.begin(); itr != aListOfPtr.end(); ++itr) 00024 { 00025 if (*itr == NULL) 00026 { 00027 MeshKit::Error badArg(MK_BAD_INPUT); 00028 badArg.set_string( 00029 "AF2Rule constructor arguments may not contain any null pointers."); 00030 throw badArg; 00031 } 00032 anArrayOfPtr[indx] = *itr; 00033 ++indx; 00034 } 00035 } 00036 00042 template<class T> 00043 void aF2RuleDeepDeletePtrArray(T** & anArrayOfPtr, int arraySize) 00044 { 00045 for (int indx = 0; indx < arraySize; ++indx) 00046 { 00047 delete anArrayOfPtr[indx]; 00048 } 00049 delete[] anArrayOfPtr; 00050 } 00051 00052 AF2Rule::AF2Rule(std::string const & ruleNameArg, unsigned int maxQuality, 00053 std::list<const AF2RuleExistVertex*> const & ruleVertices, 00054 const AF2RuleExistEdge* baselineEdge, 00055 std::list<const AF2RuleExistEdge*> const & otherRuleEdges, 00056 const AF2FreeZoneDef* freeZoneDef, 00057 std::list<const AF2RuleNewVertex*> const & ruleNewVertices, 00058 std::list<const AF2RuleNewEdge*> const & ruleNewEdges, 00059 std::list<const AF2RuleNewFace*> const & ruleNewFaces) : 00060 ruleName(ruleNameArg), 00061 maxQualityLevel(maxQuality), 00062 numExVertices(ruleVertices.size()), 00063 numExEdges(1u + otherRuleEdges.size()), 00064 freeZoneDef(freeZoneDef), 00065 numNewVertices(ruleNewVertices.size()), 00066 numNewEdges(ruleNewEdges.size()), 00067 numNewFaces(ruleNewFaces.size()) 00068 { 00069 if (baselineEdge == NULL) 00070 { 00071 MeshKit::Error badArg(MeshKit::MK_BAD_INPUT); 00072 badArg.set_string("The baseline edge may not be null."); 00073 throw badArg; 00074 } 00075 if (numExVertices < 2) 00076 { 00077 MeshKit::Error badArg(MeshKit::MK_BAD_INPUT); 00078 badArg.set_string("AF2Rule must define at least two existing vertices."); 00079 throw badArg; 00080 } 00081 aF2RuleCopyListToArray(ruleVertices, exVertices); 00082 aF2RuleCopyListToArray(otherRuleEdges, exEdges, 1u); 00083 exEdges[0] = baselineEdge; 00084 aF2RuleCopyListToArray(ruleNewVertices, newVertices); 00085 aF2RuleCopyListToArray(ruleNewEdges, newEdges); 00086 aF2RuleCopyListToArray(ruleNewFaces, newFaces); 00087 checkExEndpointsAndFindIsolatedVertices(); 00088 } 00089 00090 AF2Rule::~AF2Rule() 00091 { 00092 delete[] exIsoVertices; 00093 aF2RuleDeepDeletePtrArray(newFaces, numNewFaces); 00094 aF2RuleDeepDeletePtrArray(newEdges, numNewEdges); 00095 aF2RuleDeepDeletePtrArray(newVertices, numNewVertices); 00096 aF2RuleDeepDeletePtrArray(exEdges, numExEdges); 00097 aF2RuleDeepDeletePtrArray(exVertices, numExVertices); 00098 delete freeZoneDef; 00099 } 00100 00101 AF2Rule::AF2Rule(const AF2Rule & toCopy) : 00102 ruleName(toCopy.ruleName), 00103 maxQualityLevel(toCopy.maxQualityLevel), 00104 numExVertices(toCopy.numExVertices), 00105 numExEdges(toCopy.numExEdges), 00106 freeZoneDef(toCopy.freeZoneDef->clone()), 00107 numNewVertices(toCopy.numNewVertices), 00108 numNewEdges(toCopy.numNewEdges), 00109 numNewFaces(toCopy.numNewFaces) 00110 { 00111 MeshKit::Error notImpl(MeshKit::MK_NOT_IMPLEMENTED); 00112 notImpl.set_string("AF2Rule copy construction is not supported."); 00113 throw notImpl; 00114 } 00115 00116 AF2Rule& AF2Rule::operator=(const AF2Rule & rhs) 00117 { 00118 MeshKit::Error notImpl(MeshKit::MK_NOT_IMPLEMENTED); 00119 notImpl.set_string("AF2Rule assignment operator is not supported."); 00120 throw notImpl; 00121 } 00122 00123 void AF2Rule::checkExEndpointsAndFindIsolatedVertices() 00124 { 00125 std::set<const AF2RuleExistVertex*> endPoints; 00126 for (unsigned int exEdgeIndx = 0; exEdgeIndx < numExEdges; ++exEdgeIndx) 00127 { 00128 if (exEdgeIndx > 0 && exEdges[exEdgeIndx] == exEdges[0]) 00129 { 00130 MeshKit::Error badArg(MeshKit::MK_BAD_INPUT); 00131 badArg.set_string("The baseline edge may not be listed in the rule's other existing edges."); 00132 throw badArg; 00133 } 00134 endPoints.insert(exEdges[exEdgeIndx]->getStart()); 00135 endPoints.insert(exEdges[exEdgeIndx]->getEnd()); 00136 } 00137 00138 std::list<const AF2RuleExistVertex*> isoVertList; 00139 std::set<const AF2RuleExistVertex*> allVertSet; 00140 for (unsigned int exVtxIndx = 0; exVtxIndx < numExVertices; ++exVtxIndx) 00141 { 00142 allVertSet.insert(exVertices[exVtxIndx]); 00143 std::set<const AF2RuleExistVertex*>::iterator endPntItr = 00144 endPoints.find(exVertices[exVtxIndx]); 00145 if (endPntItr == endPoints.end()) 00146 { 00147 // the vertex is an isolated vertex rather than an endpoint of an edge 00148 isoVertList.push_back(exVertices[exVtxIndx]); 00149 } 00150 else 00151 { 00152 endPoints.erase(endPntItr); 00153 } 00154 } 00155 00156 if (!endPoints.empty()) 00157 { 00158 MeshKit::Error badArg(MeshKit::MK_BAD_INPUT); 00159 badArg.set_string("The endpoints of the rule's existing edges are not all existing vertices."); 00160 throw badArg; 00161 } 00162 00163 if (allVertSet.size() != numExVertices) 00164 { 00165 MeshKit::Error badArg(MeshKit::MK_BAD_INPUT); 00166 badArg.set_string("There is a duplicate existing vertex."); 00167 throw badArg; 00168 } 00169 00170 numExIsoVertices = isoVertList.size(); 00171 aF2RuleCopyListToArray(isoVertList, exIsoVertices); 00172 } 00173 00174 std::string AF2Rule::getName() const 00175 { 00176 return ruleName; 00177 } 00178 00179 std::map<const AF2RuleExistEdge*, std::list<const AF2Edge2D*>*>* 00180 AF2Rule::findPotentialEdgeMatches(AF2Neighborhood const & ngbhd, 00181 unsigned int matchQuality) const 00182 { 00183 // define a map to hold the potential match information 00184 std::map<const AF2RuleExistEdge*, std::list<const AF2Edge2D*>*>* matchMap = 00185 new std::map<const AF2RuleExistEdge*, std::list<const AF2Edge2D*>*>(); 00186 00187 // First match the baseline edge 00188 std::list<const AF2Edge2D*>* baselineEdgeMatches = 00189 new std::list<const AF2Edge2D*>(); 00190 if (isMatchingEdge(*(ngbhd.getBaselineEdge2D()), *exEdges[0], matchQuality)) 00191 { 00192 baselineEdgeMatches->push_back(ngbhd.getBaselineEdge2D()); 00193 } 00194 (*matchMap)[exEdges[0]] = baselineEdgeMatches; 00195 00196 // Match any other existing edges that the rule may define 00197 const std::list<const AF2Edge2D*>* ngbhdEdges = ngbhd.getEdges2D(); 00198 for (unsigned int indx = 1u; indx < numExEdges; ++indx) 00199 { 00200 const AF2RuleExistEdge* ruleEdge = exEdges[indx]; 00201 std::list<const AF2Edge2D*>* possMatches = 00202 new std::list<const AF2Edge2D*>(); 00203 for (std::list<const AF2Edge2D*>::const_iterator ngbEdgeItr = 00204 ngbhdEdges->begin(); ngbEdgeItr != ngbhdEdges->end(); ++ngbEdgeItr) 00205 { 00206 if (isMatchingEdge(**ngbEdgeItr, *ruleEdge, matchQuality)) 00207 { 00208 possMatches->push_back(*ngbEdgeItr); 00209 } 00210 } 00211 (*matchMap)[ruleEdge] = possMatches; 00212 } 00213 00214 return matchMap; 00215 } 00216 00217 std::map<const AF2RuleExistVertex*, std::list<const AF2Point2D*>*>* 00218 AF2Rule::findPotentialVertexMatches(AF2Neighborhood const & ngbhd, 00219 unsigned int matchQuality) const 00220 { 00221 const std::list<const AF2Point2D*>* ngbhdPoints = ngbhd.getPoints2D(); 00222 std::map<const AF2RuleExistVertex*, 00223 std::list<const AF2Point2D*>*>* matchMap = 00224 new std::map<const AF2RuleExistVertex*, std::list<const AF2Point2D*>*>(); 00225 for (unsigned indx = 0; indx < numExIsoVertices; ++indx) 00226 { 00227 const AF2RuleExistVertex* ruleVertex = exIsoVertices[indx]; 00228 std::list<const AF2Point2D*>* possMatches = 00229 new std::list<const AF2Point2D*>(); 00230 for (std::list<const AF2Point2D*>::const_iterator ngbPointItr = 00231 ngbhdPoints->begin(); ngbPointItr != ngbhdPoints->end(); ++ngbPointItr) 00232 { 00233 if (isMatchingVertex(**ngbPointItr, *ruleVertex, matchQuality)) 00234 { 00235 possMatches->push_back(*ngbPointItr); 00236 } 00237 } 00238 (*matchMap)[ruleVertex] = possMatches; 00239 } 00240 00241 return matchMap; 00242 } 00243 00244 bool AF2Rule::isMatchingEdge(AF2Edge2D const & edge, 00245 AF2RuleExistEdge const & ruleEdge, unsigned int matchQuality) const 00246 { 00247 if (!isMatchingVertex(*(edge.getStart()), *(ruleEdge.getStart()), 00248 matchQuality) || !isMatchingVertex(*(edge.getEnd()), 00249 *(ruleEdge.getEnd()), matchQuality)) 00250 { 00251 return false; 00252 } 00253 00254 double matchTol = 0.25 + 0.15 * matchQuality; 00255 matchTol *= matchTol; 00256 return ruleEdge.isMatching(*(edge.getStart()), *(edge.getEnd()), matchTol); 00257 } 00258 00259 bool AF2Rule::isMatchingVertex(AF2Point2D const & point, 00260 AF2RuleExistVertex const & ruleVertex, unsigned int matchQuality) const 00261 { 00262 double matchTol = 0.25 + 0.15 * matchQuality; 00263 matchTol *= matchTol; 00264 return ruleVertex.isMatching(point, matchTol); 00265 } 00266 00267 void AF2Rule::applyRule(AF2Neighborhood const & ngbhd, 00268 unsigned int matchQuality, AF2RuleAppVisitor & visitor) const 00269 { 00270 if (matchQuality < maxQualityLevel) 00271 { 00272 return; 00273 } 00274 00275 std::map<const AF2RuleExistEdge*, std::list<const AF2Edge2D*>*>* 00276 matchingEdgesMap = findPotentialEdgeMatches(ngbhd, matchQuality); 00277 std::map<const AF2RuleExistVertex*, std::list<const AF2Point2D*>*>* 00278 matchingVerticesMap = findPotentialVertexMatches(ngbhd, matchQuality); 00279 00280 AF2Binding binding; 00281 00282 std::stack<std::list<const AF2Edge2D*>::const_iterator> edgeMatchItrStack; 00283 unsigned int edgeToMatchIndx = 0; 00284 --edgeToMatchIndx; 00285 bool consistentMatch = true; 00286 const AF2RuleExistEdge* edgeToMatch = NULL; 00287 while (true) 00288 { 00289 if (consistentMatch) 00290 { 00291 ++edgeToMatchIndx; 00292 if (edgeToMatchIndx == numExEdges) 00293 { 00294 // all edges have been matched 00295 // stage two matches any isolated vertices and proceeds 00296 // to stages three and four 00297 applyRuleStageTwo(ngbhd, matchQuality, visitor, 00298 matchingVerticesMap, binding); 00299 // now mark the match as inconsistent, so that the edge binding 00300 // for the final edge is released and the search continues 00301 consistentMatch = false; 00302 } 00303 else 00304 { 00305 // not all edges have been matched yet, so set up to attempt to 00306 // match the next edge given the current binding 00307 edgeToMatch = exEdges[edgeToMatchIndx]; 00308 edgeMatchItrStack.push((*matchingEdgesMap)[edgeToMatch]->begin()); 00309 } 00310 } 00311 00312 if (!consistentMatch) 00313 { 00314 if (edgeToMatchIndx == 0) 00315 { 00316 // all edges beyond the base edge have examined all possible matches 00317 break; 00318 } 00319 --edgeToMatchIndx; 00320 edgeToMatch = exEdges[edgeToMatchIndx]; 00321 // release the edge binding from the last time edgeToMatch was bound 00322 binding.release(edgeToMatch); 00323 } 00324 00325 consistentMatch = false; 00326 std::list<const AF2Edge2D*>::const_iterator itr = edgeMatchItrStack.top(); 00327 edgeMatchItrStack.pop(); 00328 for (; itr != (*matchingEdgesMap)[edgeToMatch]->end(); ++itr) 00329 { 00330 // check consistency 00331 consistentMatch = true; 00332 if (!binding.isConsistent(edgeToMatch, *itr)) 00333 { 00334 consistentMatch = false; 00335 } 00336 else 00337 { 00338 // bind the edge and store the next position of the iterator 00339 // on the iterator stack for later examination 00340 binding.bind(edgeToMatch, *itr); 00341 edgeMatchItrStack.push(++itr); 00342 00343 // break out of this loop and proceed to bind other edges or vertices 00344 // or check the free zone and finish applying the rule 00345 break; 00346 } 00347 } 00348 } 00349 } 00350 00351 void AF2Rule::applyRuleStageTwo(AF2Neighborhood const & ngbhd, 00352 unsigned int matchQuality, AF2RuleAppVisitor & visitor, 00353 std::map<const AF2RuleExistVertex*, std::list<const AF2Point2D*>*>* const & 00354 matchingVerticesMap, AF2Binding & binding) const 00355 { 00356 // Note: At this point it would be possible to filter the lists 00357 // of vertices that are potential matches, removing any potential 00358 // matches that are already bound as endpoints of edges, but it's 00359 // not clear that the performance improvement, if any, would offset 00360 // the additional memory for storing the filtered list and the 00361 // additional computation. 00362 00363 std::stack<std::list<const AF2Point2D*>::const_iterator> vertexMatchItrStack; 00364 unsigned int vertexToMatchIndx = 0; 00365 --vertexToMatchIndx; 00366 bool consistentMatch = true; 00367 const AF2RuleExistVertex* vertexToMatch = NULL; 00368 while (true) 00369 { 00370 if (consistentMatch) 00371 { 00372 ++vertexToMatchIndx; 00373 if (vertexToMatchIndx == numExIsoVertices) 00374 { 00375 // all edges and all vertices have been matched 00376 applyRuleStageThree(ngbhd, matchQuality, visitor, binding); 00377 // now mark the match as inconsistent, so that the vertex binding 00378 // for the final vertex is released and the search continues 00379 // or (if there were no vertices to match) the search is terminated 00380 consistentMatch = false; 00381 } 00382 else 00383 { 00384 // not all isolated vertices have been matched yet, so set up to 00385 // attempt to match the next vertex given the current binding 00386 vertexToMatch = exIsoVertices[vertexToMatchIndx]; 00387 vertexMatchItrStack.push( 00388 (*matchingVerticesMap)[vertexToMatch]->begin()); 00389 } 00390 } 00391 00392 if (!consistentMatch) 00393 { 00394 if (vertexToMatchIndx == 0) 00395 { 00396 // all isolated vertices have explored all possible matches 00397 break; 00398 } 00399 --vertexToMatchIndx; 00400 vertexToMatch = exIsoVertices[vertexToMatchIndx]; 00401 // release the vertex binding from the last time vertexToMatch was bound 00402 binding.release(vertexToMatch); 00403 } 00404 00405 consistentMatch = false; 00406 std::list<const AF2Point2D*>::const_iterator itr = 00407 vertexMatchItrStack.top(); 00408 vertexMatchItrStack.pop(); 00409 for (; itr != (*matchingVerticesMap)[vertexToMatch]->end(); ++itr) 00410 { 00411 // check consistency 00412 consistentMatch = true; 00413 if (!binding.isConsistent(vertexToMatch, *itr)) 00414 { 00415 consistentMatch = false; 00416 } 00417 else 00418 { 00419 // bind the vertex and store the next position of the iterator 00420 // on the iterator stack for later examination 00421 binding.bind(vertexToMatch, *itr); 00422 vertexMatchItrStack.push(++itr); 00423 00424 // break out of this loop and proceed to bind other vertices 00425 // or check the free zone and finish applying the rule 00426 break; 00427 } 00428 } 00429 } 00430 } 00431 00432 void AF2Rule::applyRuleStageThree(AF2Neighborhood const & ngbhd, 00433 unsigned int matchQuality, AF2RuleAppVisitor & visitor, 00434 AF2Binding const & binding) const 00435 { 00436 bool emptyFreeZone = true; 00437 00438 AF2FreeZone* freeZone = freeZoneDef->makeFreeZone(binding, matchQuality); 00439 if (!freeZone->isConvex()) 00440 { 00441 emptyFreeZone = false; 00442 } 00443 00444 const std::list<const AF2Point2D*>* ngbhdPoints = ngbhd.getPoints2D(); 00445 for (std::list<const AF2Point2D*>::const_iterator itr = ngbhdPoints->begin(); 00446 emptyFreeZone && itr != ngbhdPoints->end(); ++itr) 00447 { 00448 emptyFreeZone = !freeZone->nearContains(**itr); 00449 } 00450 00451 const std::list<const AF2Edge2D*>* ngbhdEdges = ngbhd.getEdges2D(); 00452 for (std::list<const AF2Edge2D*>::const_iterator itr = ngbhdEdges->begin(); 00453 emptyFreeZone && itr != ngbhdEdges->end(); ++itr) 00454 { 00455 emptyFreeZone = !freeZone->nearIntersects( 00456 *((*itr)->getStart()), *((*itr)->getEnd())); 00457 } 00458 00459 delete freeZone; 00460 00461 if (emptyFreeZone) 00462 { 00463 // This binding would be an acceptable way to apply the rule, so 00464 // build an AF2RuleApplication and pass it to the visitor 00465 const AF2Point2D** newPointsArray = new const AF2Point2D*[numNewVertices]; 00466 std::list<const AF2Point2D*> newPointsList; 00467 for (unsigned int nvi = 0; nvi < numNewVertices; ++nvi) 00468 { 00469 newPointsArray[nvi] = 00470 new AF2Point2D(newVertices[nvi]->getLocation(binding)); 00471 newPointsList.push_back(newPointsArray[nvi]); 00472 } 00473 00474 std::list<const AF2Polygon2D*> newPolygonsList; 00475 for (unsigned int nfi = 0; nfi < numNewFaces; ++nfi) 00476 { 00477 std::list<const AF2Point2D*> polygonVertices; 00478 for (unsigned int fvi = 0; fvi < newFaces[nfi]->getNumVertices(); ++fvi) 00479 { 00480 unsigned int polyVertIndex = newFaces[nfi]->getVertexIndex(fvi); 00481 if (polyVertIndex < numExVertices) 00482 { 00483 polygonVertices.push_back(binding.getBoundValue( 00484 exVertices[polyVertIndex])); 00485 } 00486 else 00487 { 00488 polygonVertices.push_back( 00489 newPointsArray[polyVertIndex - numExVertices]); 00490 } 00491 } 00492 newPolygonsList.push_back(new AF2Polygon2D(polygonVertices)); 00493 } 00494 00495 AF2RuleApplication* ruleApplication = 00496 new AF2RuleApplication(newPointsList, newPolygonsList); 00497 visitor.visit(*ruleApplication); 00498 00499 // clean up memory allocated to define the rule application 00500 delete ruleApplication; 00501 for (std::list<const AF2Polygon2D*>::const_iterator itr = 00502 newPolygonsList.begin(); itr != newPolygonsList.end(); ++itr) 00503 { 00504 delete *itr; 00505 } 00506 for (unsigned int nvi = 0; nvi < numNewVertices; ++nvi) 00507 { 00508 delete newPointsArray[nvi]; 00509 } 00510 delete[] newPointsArray; 00511 } 00512 }