MeshKit  1.0
AF2Rule.cpp
Go to the documentation of this file.
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 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines