MeshKit  1.0
AF2Front.cpp
Go to the documentation of this file.
00001 #include "meshkit/AF2Front.hpp"
00002 
00003 // C++
00004 #include <algorithm>
00005 #include <cmath>
00006 
00007 // MeshKit
00008 #include "meshkit/Error.hpp"
00009 #include "meshkit/AF2LocalTransform.hpp"
00010 
00011 bool EndPointLess::operator()(const AF2Edge3D* const & oneEdge,
00012     const AF2Edge3D* const & otherEdge) const
00013 {
00014   if (oneEdge->getStart()->getLocalId() < otherEdge->getStart()->getLocalId())
00015   {
00016     return true;
00017   }
00018   if (oneEdge->getStart()->getLocalId() > otherEdge->getStart()->getLocalId())
00019   {
00020     return false;
00021   }
00022   // otherwise the start endpoints are equal
00023   if (oneEdge->getEnd()->getLocalId() < otherEdge->getEnd()->getLocalId())
00024   {
00025     return true;
00026   }
00027   return false;
00028 }
00029 
00030 AF2Front::AF2Front() : points(), edges(), qualityCount(4, 0u)
00031 {
00032 }
00033 
00034 AF2Front::~AF2Front()
00035 {
00036   typedef std::set<AF2Edge3D*>::iterator EdgeSetItr;
00037   for (EdgeSetItr edgeItr = edges.begin(); edgeItr != edges.end(); ++edgeItr)
00038   {
00039     delete *edgeItr;
00040   }
00041 }
00042 
00043 AF2Front::AF2Front(const AF2Front & toCopy)
00044 {
00045   MeshKit::Error notImpl(MeshKit::MK_NOT_IMPLEMENTED);
00046   notImpl.set_string("AF2Front copy construction is not supported.");
00047   throw notImpl;
00048 }
00049 
00050 AF2Front& AF2Front::operator=(const AF2Front & rhs)
00051 {
00052   MeshKit::Error notImpl(MeshKit::MK_NOT_IMPLEMENTED);
00053   notImpl.set_string("AF2Front assignment operator is not supported.");
00054   throw notImpl;
00055 }
00056 
00057 void AF2Front::qualityDecreased(const AF2Edge3D* const & anEdge)
00058 {
00059   unsigned int curQual = anEdge->getQualityLevel();
00060   if (curQual > qualityCount.size())
00061   {
00062     qualityCount.resize(curQual, 0u);
00063   }
00064   ++qualityCount[curQual - 1];
00065   --qualityCount[curQual - 2];
00066 }
00067 
00068 void AF2Front::addPoint(AF2Point3D* pointPtr)
00069 {
00070   if (points.find(pointPtr) != points.end())
00071   {
00072     MeshKit::Error duplicate(MeshKit::MK_BAD_INPUT);
00073     duplicate.set_string("The point is already on the advancing front.");
00074     throw duplicate;
00075   }
00076   points[pointPtr] = 0;
00077 }
00078 
00079 void AF2Front::advanceFront(std::list<AF2Edge3D*> edgeList)
00080 {
00081   typedef std::map<AF2Point3D*, int>::iterator PointCountItr;
00082   typedef std::set<AF2Edge3D*>::iterator EdgeSetItr;
00083   typedef std::list<AF2Edge3D*>::iterator EdgeListItr;
00084 
00085   // verify validity of endpoints, which could throw exception,
00086   // before doing any other processing
00087   for (EdgeListItr itr = edgeList.begin(); itr != edgeList.end(); ++itr)
00088   {
00089     PointCountItr startPntItr = points.find((*itr)->getStart());
00090     PointCountItr endPntItr = points.find((*itr)->getEnd());
00091     if (startPntItr == points.end() || endPntItr == points.end())
00092     {
00093       MeshKit::Error badArg(MeshKit::MK_BAD_INPUT);
00094       badArg.set_string(
00095           "One or both endpoints of an edge are not on the advancing front.");
00096       throw badArg;
00097     }
00098     if ((*itr)->getQualityLevel() != 1u)
00099     {
00100       MeshKit::Error badArg(MeshKit::MK_BAD_INPUT);
00101       badArg.set_string(
00102           "Edges added to the advancing front must have quality level 1.");
00103       throw badArg;
00104     }
00105   }
00106 
00107   // decide which half edges need to be added
00108   // and which (reverse) half edges need to be removed
00109   std::list<AF2Edge3D*> edgesToAdd;
00110   std::list<EdgeSetItr> edgesToRemove;
00111 
00112   for (EdgeListItr itr = edgeList.begin(); itr != edgeList.end(); ++itr)
00113   {
00114     AF2Edge3D reverseEdge((*itr)->getEnd(), (*itr)->getStart());
00115     EdgeSetItr revEdgeItr = edges.find(&reverseEdge);
00116     if (revEdgeItr != edges.end())
00117     {
00118       // prepare for later processing of the reverse half edge that was
00119       // allocated on the heatp to remove it from the edge set and delete it
00120       // don't delete it now, since that would make it more difficult to
00121       //   determine whether its endpoints should be deleted
00122       edgesToRemove.push_back(revEdgeItr);
00123       // right now delete the forward half edge that was allocated on the heap
00124       delete *itr;
00125     }
00126     else
00127     {
00128       // prepare for later processing of the forward half edge
00129       // don't add it now, since that would prevent adding both half edges
00130       //   of an "isolated" edge
00131       edgesToAdd.push_back(*itr);
00132     }
00133   }
00134 
00135   // add the half edges that need to be added
00136   for (EdgeListItr itr = edgesToAdd.begin(); itr != edgesToAdd.end(); ++itr)
00137   {
00138     // add it to the set of edges
00139     edges.insert(*itr);
00140     // start tracking the edge's quality level
00141     ++qualityCount[0];
00142     (*itr)->setObserver(this);
00143     // increase the count of the number of edges incident to each endpoint
00144     ++points[(*itr)->getStart()];
00145     ++points[(*itr)->getEnd()];
00146     // update the distance to the boundary (locally)
00147     // * Note * The distance to the boundary may be globally inaccurate
00148     // after this update, but this agrees with how NetGen did the update.
00149     // It would be possible to cascade the distance to boundary updates
00150     // and ensure globally accuracy, but that might affect a lot of points.
00151     unsigned int maxDist = 1 + std::min(
00152         (*itr)->getStart()->getDistanceToBoundary(),
00153         (*itr)->getEnd()->getDistanceToBoundary());
00154     (*itr)->getStart()->limitDistanceToBoundary(maxDist);
00155     (*itr)->getEnd()->limitDistanceToBoundary(maxDist);
00156   }
00157 
00158   // remove the half edges that need to be removed and any endpoints of
00159   // those edges that have no incident edges after the edge is removed
00160   for (std::list<EdgeSetItr>::iterator itr = edgesToRemove.begin();
00161       itr != edgesToRemove.end(); ++itr)
00162   {
00163     EdgeSetItr edgeItr = *itr;
00164     // decrease the count of the number of edges incident to each endpoint
00165     --points[(*edgeItr)->getStart()];
00166     --points[(*edgeItr)->getEnd()];
00167     // remove endpoints from points if they now have zero incident edges
00168     if (points[(*edgeItr)->getStart()] == 0u)
00169     {
00170       points.erase((*edgeItr)->getStart());
00171     }
00172     if (points[(*edgeItr)->getEnd()] == 0u)
00173     {
00174       points.erase((*edgeItr)->getEnd());
00175     }
00176     // stop tracking the quality level of the edge
00177     --qualityCount[(*edgeItr)->getQualityLevel() - 1u];
00178     // delete the edge object that was allocated on the heap
00179     delete *edgeItr;
00180     // remove the (now dangling) pointer to the edge from the edge set
00181     edges.erase(edgeItr);
00182   }
00183 }
00184 
00185 bool AF2Front::isEmpty() const
00186 {
00187   return edges.empty() && points.empty();
00188 }
00189 
00190 unsigned int AF2Front::getMaximumQuality() const
00191 {
00192   for (unsigned int qualityLevel = 1;
00193       qualityLevel <= qualityCount.size(); ++qualityLevel)
00194   {
00195     if (qualityCount[qualityLevel - 1] > 0)
00196     {
00197       return qualityLevel;
00198     }
00199   }
00200 
00201   return 0u;
00202 }
00203 
00204 AF2Neighborhood* AF2Front::selectNeighborhood(
00205     const AF2LocalTransformMaker* const & transformMaker) const
00206 {
00207   typedef std::set<AF2Edge3D*>::const_iterator EdgeSetItr;
00208   typedef std::map<AF2Point3D*, int>::const_iterator PointCountItr;
00209 
00210   // Select a baseline edge that minimizes a metric value for the metric
00211   // edge quality level + sum of endpoint distances to boundary.
00212   // The current implementation loops through all of the edges
00213   // to find an edge with minimal metric value.  This could be made faster
00214   // using a C++ priority queue, updating each time the metric value changes.
00215   AF2Edge3D* baselineEdge = NULL;
00216   unsigned int minMetricVal;
00217   for (EdgeSetItr edgeItr = edges.begin(); edgeItr != edges.end(); ++edgeItr)
00218   {
00219     if (baselineEdge == NULL)
00220     {
00221       minMetricVal = (*edgeItr)->getQualityLevel() +
00222           (*edgeItr)->getStart()->getDistanceToBoundary() +
00223           (*edgeItr)->getEnd()->getDistanceToBoundary();
00224       baselineEdge = *edgeItr;
00225     }
00226     else
00227     {
00228       unsigned int metricVal = (*edgeItr)->getQualityLevel() +
00229           (*edgeItr)->getStart()->getDistanceToBoundary() +
00230           (*edgeItr)->getEnd()->getDistanceToBoundary();
00231       if (metricVal < minMetricVal)
00232       {
00233         metricVal = minMetricVal;
00234         baselineEdge = *edgeItr;
00235       }
00236     }
00237   }
00238 
00239   // throw an exception if no baseline edge was found
00240   if (baselineEdge == NULL)
00241   {
00242     MeshKit::Error fail(MeshKit::MK_FAILURE);
00243     fail.set_string("The advancing front has no edges.");
00244     throw fail;
00245   }
00246 
00247   // determine the neighborhood size from the length and quality
00248   // level of the baseline edge
00249   AF2Point3D* baseStart = baselineEdge->getStart();
00250   AF2Point3D* baseEnd = baselineEdge->getEnd();
00251   double xDiff = baseEnd->getX() - baseStart->getX();
00252   double yDiff = baseEnd->getY() - baseStart->getY();
00253   double zDiff = baseEnd->getZ() - baseStart->getZ();
00254   double sqLen = xDiff * xDiff + yDiff * yDiff + zDiff * zDiff;
00255   unsigned int qLevelFactor = std::min(baselineEdge->getQualityLevel(), 7u);
00256   double ngbhdSize = 4.0 * (3u + qLevelFactor) * (3u + qLevelFactor) * sqLen;
00257 
00258   // create lists to hold the points and (other) edges in the neighborhood
00259   std::list<AF2Point3D*> ngbhdPoints;
00260   std::list<const AF2Edge3D*> ngbhdEdges;
00261   // create a set to track points included in the neighorhood and avoid
00262   // duplicating them if they are endpoints of multiple neighborhood edges
00263   std::set<AF2Point3D*> ngbhdPointSet;
00264 
00265   // find edges that are close enough to the baseline edge
00266   // to be included in the neighborhood
00267   AF2Point3D* edgeStart = NULL;
00268   AF2Point3D* edgeEnd = NULL;
00269   double edgeXDiff = 0.0;
00270   double edgeYDiff = 0.0;
00271   double edgeZDiff = 0.0;
00272   double edgeSqLen = 0.0;
00273   double dotProd = 0.0;
00274   for (EdgeSetItr edgeItr = edges.begin(); edgeItr != edges.end(); ++edgeItr)
00275   {
00276     // skip the baseline edge to avoid duplicating it in the neighborhood
00277     if ((*edgeItr) == baselineEdge)
00278     {
00279       continue;
00280     }
00281 
00282     // calculate components of vector along the direction of the edge
00283     // and the squared length of the edge
00284     edgeStart = (*edgeItr)->getStart();
00285     edgeEnd = (*edgeItr)->getEnd();
00286     edgeXDiff = edgeEnd->getX() - edgeStart->getX();
00287     edgeYDiff = edgeEnd->getY() - edgeStart->getY();
00288     edgeZDiff = edgeEnd->getZ() - edgeStart->getZ();
00289     edgeSqLen = edgeXDiff * edgeXDiff +
00290         edgeYDiff * edgeYDiff + edgeZDiff * edgeZDiff;
00291 
00292     // calculate components of vector from edge start point to base start point
00293     xDiff = baseStart->getX() - edgeStart->getX();
00294     yDiff = baseStart->getY() - edgeStart->getY();
00295     zDiff = baseStart->getZ() - edgeStart->getZ();
00296 
00297     // calculate the dot product of the two vectors
00298     dotProd = edgeXDiff * xDiff + edgeYDiff * yDiff + edgeZDiff * zDiff;
00299 
00300     // calculate the components of the vector from the baseline edge
00301     // start point to the closest point on the edge, placing the results
00302     // in (and reusing the variables) xDiff, yDiff, and zDiff
00303     if (dotProd < 0)
00304     {
00305       // the orthogonal projection of the baseline edge start point onto
00306       // the line that contains the current edge lies outside the edge
00307       // and the edge start point is closest to the baseline edge start point
00308 
00309       // the vector from the edge start point to the baseline edge start
00310       // point is correct, and xDiff, yDiff, and zDiff already has that vector
00311       // --> do nothing
00312     }
00313     else if (dotProd > edgeSqLen)
00314     {
00315       // the orthogonal projection of the baseline edge start point onto
00316       // the line that contains the current edge lies outside the edge
00317       // and the edge end point is closest to the baseline edge start point
00318 
00319       // the vector from the edge end point to the baseline edge start
00320       // point is the one that is needed
00321       xDiff = baseStart->getX() - edgeEnd->getX();
00322       yDiff = baseStart->getY() - edgeEnd->getY();
00323       zDiff = baseStart->getZ() - edgeEnd->getZ();
00324     }
00325     else
00326     {
00327       // the orthogonal projection of the baseline edge start point onto
00328       // the line that contains the current edge lies on the edge
00329       // and is the closest point on the edge to the baseline edge start point
00330 
00331       // calculate the components of the projection of the vector from the
00332       // edge start point to the baseline edge start point onto the vector
00333       // in the direction of the edge, reusing edge difference variables
00334       edgeXDiff = dotProd * edgeXDiff / edgeSqLen;
00335       edgeYDiff = dotProd * edgeYDiff / edgeSqLen;
00336       edgeZDiff = dotProd * edgeZDiff / edgeSqLen;
00337 
00338       // calculate the components of the projection of the vector from the
00339       // edge start point to the baseline edge start point onto the plane
00340       // orthogonal to the direction of the edge
00341       xDiff = xDiff - edgeXDiff;
00342       yDiff = yDiff - edgeYDiff;
00343       zDiff = zDiff - edgeZDiff;
00344     }
00345 
00346     // calculate the square of the length of said vector, which is also the
00347     // square of the distance from the edge to the baseline edge start point
00348     sqLen = xDiff * xDiff + yDiff * yDiff + zDiff * zDiff;
00349 
00350     // if the edge is close enough, add it and its endpoints
00351     // to the neighborhood
00352     if (sqLen < ngbhdSize)
00353     {
00354       ngbhdEdges.push_back(*edgeItr);
00355       if (ngbhdPointSet.find(edgeStart) == ngbhdPointSet.end())
00356       {
00357         ngbhdPointSet.insert(edgeStart);
00358         ngbhdPoints.push_back(edgeStart);
00359       }
00360       if (ngbhdPointSet.find(edgeEnd) == ngbhdPointSet.end())
00361       {
00362         ngbhdPointSet.insert(edgeEnd);
00363         ngbhdPoints.push_back(edgeEnd);
00364       }
00365     }
00366   }
00367 
00368   // find points that are close enough to the baseline edge
00369   // to be included in the neighborhood
00370   for (PointCountItr itr = points.begin(); itr != points.end(); ++itr)
00371   {
00372     AF2Point3D* frontPoint = itr->first;
00373 
00374     // calculate the square of the distance from the baseline edge start point
00375     xDiff = frontPoint->getX() - baseStart->getX();
00376     yDiff = frontPoint->getY() - baseStart->getY();
00377     zDiff = frontPoint->getZ() - baseStart->getZ();
00378     sqLen = xDiff * xDiff + yDiff * yDiff + zDiff * zDiff;
00379 
00380     // if the distance is small enough and the point has not been added
00381     // to the neighborhood yet, add it to the neighborhood
00382     if (sqLen < ngbhdSize &&
00383         ngbhdPointSet.find(frontPoint) == ngbhdPointSet.end())
00384     {
00385       ngbhdPointSet.insert(frontPoint);
00386       ngbhdPoints.push_back(frontPoint);
00387     }
00388   }
00389 
00390   // use the transform maker to make a local transform appropriate
00391   // to the neighborhood
00392   AF2LocalTransform* localTransform =
00393       transformMaker->makeLocalTransform(ngbhdPoints, baselineEdge, ngbhdEdges);
00394 
00395   // build and return the neighborhood object
00396   return new AF2Neighborhood(
00397       ngbhdPoints, baselineEdge, ngbhdEdges, localTransform);
00398 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines