Changeset 71b20e
- Timestamp:
- Dec 19, 2009, 7:32:24 PM (15 years ago)
- Branches:
- Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, CombiningParticlePotentialParsing, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_BoundInBox_CenterInBox_MoleculeActions, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_PopActions, Fix_QtFragmentList_sorted_selection, Fix_Restrictedkeyset_FragmentMolecule, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, Fix_fitting_potentials, Fixes, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, FragmentAction_writes_AtomFragments, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, ImplicitCharges, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, MoreRobust_FragmentAutomation, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PdbParser_setsAtomName, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, Rewrite_FitPartialCharges, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, SaturateAtoms_singleDegree, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, Switchable_LogView, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, TremoloParser_setsAtomName, Ubuntu_1604_changes, stable
- Children:
- c15ca2
- Parents:
- 3930eb
- Location:
- src
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
src/boundary.cpp
r3930eb r71b20e 654 654 * \param *out output stream for debugging 655 655 * \param *mol molecule with atoms and bonds 656 * \param * &TesselStruct Tesselation with boundary triangles656 * \param *TesselStruct Tesselation with boundary triangles 657 657 * \param *filename prefix of filename 658 658 * \param *extraSuffix intermediate suffix 659 659 */ 660 void StoreTrianglesinFile(const molecule * const mol, const Tesselation * &TesselStruct, const char *filename, const char *extraSuffix)660 void StoreTrianglesinFile(const molecule * const mol, const Tesselation * const TesselStruct, const char *filename, const char *extraSuffix) 661 661 { 662 662 Info FunctionInfo(__func__); … … 789 789 * \param configuration contains box dimensions 790 790 * \param distance[NDIM] distance between filling molecules in each direction 791 * \param epsilon distance to surface which is not filled 791 792 * \param RandAtomDisplacement maximum distance for random displacement per atom 792 793 * \param RandMolDisplacement maximum distance for random displacement per filler molecule … … 794 795 * \return *mol pointer to new molecule with filled atoms 795 796 */ 796 molecule * FillBoxWithMolecule(MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandomAtomDisplacement, double RandomMolDisplacement,bool DoRandomRotation)797 molecule * FillBoxWithMolecule(MoleculeListClass *List, molecule *filler, config &configuration, const double distance[NDIM], const double epsilon, const double RandomAtomDisplacement, const double RandomMolDisplacement, const bool DoRandomRotation) 797 798 { 798 799 Info FunctionInfo(__func__); … … 817 818 for (MoleculeList::iterator ListRunner = List->ListOfMolecules.begin(); ListRunner != List->ListOfMolecules.end(); ListRunner++) { 818 819 Log() << Verbose(1) << "Pre-creating linked cell lists for molecule " << *ListRunner << "." << endl; 819 LCList[i] = new LinkedCell((*ListRunner), 5.); // get linked cell list 820 if (TesselStruct[i] == NULL) { 821 Log() << Verbose(1) << "Pre-creating tesselation for molecule " << *ListRunner << "." << endl; 822 FindNonConvexBorder((*ListRunner), TesselStruct[i], (const LinkedCell *&)LCList[i], 5., NULL); 823 } 820 LCList[i] = new LinkedCell((*ListRunner), 10.); // get linked cell list 821 Log() << Verbose(1) << "Pre-creating tesselation for molecule " << *ListRunner << "." << endl; 822 TesselStruct[i] = NULL; 823 FindNonConvexBorder((*ListRunner), TesselStruct[i], (const LinkedCell *&)LCList[i], 5., NULL); 824 824 i++; 825 825 } … … 835 835 FillerDistance.Init(distance[0], distance[1], distance[2]); 836 836 FillerDistance.InverseMatrixMultiplication(M); 837 Log() << Verbose(1) << "INFO: Grid steps are "; 838 for(int i=0;i<NDIM;i++) { 837 for(int i=0;i<NDIM;i++) 839 838 N[i] = (int) ceil(1./FillerDistance.x[i]); 840 Log() << Verbose(1) << N[i]; 841 if (i != NDIM-1) 842 Log() << Verbose(1)<< ", "; 843 else 844 Log() << Verbose(1) << "." << endl; 845 } 839 Log() << Verbose(1) << "INFO: Grid steps are " << N[0] << ", " << N[1] << ", " << N[2] << "." << endl; 846 840 847 841 // go over [0,1]^3 filler grid … … 862 856 FillIt = false; 863 857 } else { 864 FillIt = FillIt && (!TesselStruct[i]->IsInnerPoint(CurrentPosition, LCList[i])); 858 const bool FillResult = (!TesselStruct[i]->IsInnerPoint(CurrentPosition, LCList[i], epsilon)); 859 FillIt = FillIt && FillResult; 860 if (FillResult) { 861 Log() << Verbose(1) << "INFO: Position at " << CurrentPosition << " is outer point." << endl; 862 } else { 863 Log() << Verbose(1) << "INFO: Position at " << CurrentPosition << " is inner point." << endl; 864 } 865 865 i++; 866 866 } 867 867 } 868 868 869 if ( FillIt) {869 if (!FillIt) { 870 870 // fill in Filler 871 871 Log() << Verbose(2) << "Space at " << CurrentPosition << " is unoccupied by any molecule, filling in." << endl; … … 931 931 } 932 932 Free(&M); 933 934 // output to file 935 TesselStruct[0]->LastTriangle = NULL; 936 StoreTrianglesinFile(Filling, TesselStruct[0], "Tesselated", ".dat"); 937 933 938 for (size_t i=0;i<List->ListOfMolecules.size();i++) { 934 939 delete(LCList[i]); -
src/boundary.hpp
r3930eb r71b20e 49 49 50 50 double ConvexizeNonconvexEnvelope(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename); 51 molecule * FillBoxWithMolecule(MoleculeListClass *List, molecule *filler, config &configuration, double distance[NDIM], double RandAtomDisplacement, double RandMolDisplacement,bool DoRandomRotation);51 molecule * FillBoxWithMolecule(MoleculeListClass *List, molecule *filler, config &configuration, const double distance[NDIM], const double epsilon, const double RandomAtomDisplacement, const double RandomMolDisplacement, const bool DoRandomRotation); 52 52 void FindConvexBorder(const molecule* const mol, Tesselation *&TesselStruct, const LinkedCell *LCList, const char *filename); 53 53 Vector* FindEmbeddingHole(MoleculeListClass *mols, molecule *srcmol); … … 58 58 void PrepareClustersinWater(config *configuration, molecule *mol, double ClusterVolume, double celldensity); 59 59 bool RemoveAllBoundaryPoints(class Tesselation *&TesselStruct, const molecule * const mol, const char * const filename); 60 void StoreTrianglesinFile(const molecule * const mol, const Tesselation * &TesselStruct, const char *filename, const char *extraSuffix);60 void StoreTrianglesinFile(const molecule * const mol, const Tesselation * const TesselStruct, const char *filename, const char *extraSuffix); 61 61 double VolumeOfConvexEnvelope(class Tesselation *TesselStruct, class config *configuration); 62 62 -
src/molecule.hpp
r3930eb r71b20e 110 110 TesselPoint *GetPoint() const ; 111 111 TesselPoint *GetTerminalPoint() const ; 112 int GetMaxId() const; 112 113 void GoToNext() const ; 113 114 void GoToPrevious() const ; -
src/molecule_pointcloud.cpp
r3930eb r71b20e 50 50 }; 51 51 52 /** Return the greatest index of all atoms in the list. 53 * \return greatest index 54 */ 55 int molecule::GetMaxId() const 56 { 57 return last_atom; 58 }; 59 52 60 /** Go to next atom. 53 61 * Stops at last one. -
src/tesselation.cpp
r3930eb r71b20e 482 482 { 483 483 Info FunctionInfo(__func__); 484 Log() << Verbose(1) << "INFO: Checking " << Points[0] << "," << Points[1] << "," << Points[2] << " against " << endpoints[0] << "," << endpoints[1] << "," << endpoints[2] << "." << endl; 484 485 return (((endpoints[0] == Points[0]) 485 486 || (endpoints[0] == Points[1]) … … 2986 2987 { 2987 2988 Info FunctionInfo(__func__); 2988 TesselPoint *trianglePoints[3]; 2989 TesselPoint *SecondPoint = NULL; 2990 list<BoundaryTriangleSet*> *triangles = NULL; 2989 PointMap::const_iterator FindPoint; 2990 int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 2991 2991 2992 2992 if (LinesOnBoundary.empty()) { 2993 eLog() << Verbose(1) << " Error: There is no tesselation structure to compare the point with, please create one first.";2993 eLog() << Verbose(1) << "There is no tesselation structure to compare the point with, please create one first." << endl; 2994 2994 return NULL; 2995 2995 } 2996 Log() << Verbose(1) << "Finding closest Tesselpoint to " << *x << " ... " << endl; 2997 trianglePoints[0] = FindClosestPoint(x, SecondPoint, LC); 2998 2999 // check whether closest point is "too close" :), then it's inside 3000 if (trianglePoints[0] == NULL) { 2996 2997 // gather all points close to the desired one 2998 LC->SetIndexToVector(x); // ignore status as we calculate bounds below sensibly 2999 for(int i=0;i<NDIM;i++) // store indices of this cell 3000 N[i] = LC->n[i]; 3001 Log() << Verbose(1) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl; 3002 3003 set<BoundaryPointSet *> points; 3004 LC->GetNeighbourBounds(Nlower, Nupper); 3005 //Log() << Verbose(1) << endl; 3006 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 3007 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 3008 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 3009 const LinkedNodes *List = LC->GetCurrentCell(); 3010 //Log() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl; 3011 if (List != NULL) { 3012 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) { 3013 FindPoint = PointsOnBoundary.find((*Runner)->nr); 3014 if (FindPoint != PointsOnBoundary.end()) 3015 points.insert(FindPoint->second); 3016 } 3017 } else { 3018 eLog() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl; 3019 } 3020 } 3021 3022 // check whether we found some points 3023 if (points.empty()) { 3024 Log() << Verbose(1) << "There is no nearest triangle, too far away from the surface." << endl; 3025 return NULL; 3026 } 3027 3028 // for each point, check its lines, remember closest 3029 Log() << Verbose(1) << "Finding closest BoundaryLine to " << *x << " ... " << endl; 3030 BoundaryLineSet *ClosestLine = NULL; 3031 double MinDistance = -1.; 3032 Vector helper; 3033 Vector Center; 3034 Vector BaseLine; 3035 for (set<BoundaryPointSet *>::iterator Runner = points.begin(); Runner != points.end(); Runner++) { 3036 for (LineMap::iterator LineRunner = (*Runner)->lines.begin(); LineRunner != (*Runner)->lines.end(); LineRunner++) { 3037 // calculate closest point on line to desired point 3038 helper.CopyVector((LineRunner->second)->endpoints[0]->node->node); 3039 helper.AddVector((LineRunner->second)->endpoints[1]->node->node); 3040 helper.Scale(0.5); 3041 Center.CopyVector(x); 3042 Center.SubtractVector(&helper); 3043 BaseLine.CopyVector((LineRunner->second)->endpoints[0]->node->node); 3044 BaseLine.SubtractVector((LineRunner->second)->endpoints[1]->node->node); 3045 Center.ProjectOntoPlane(&BaseLine); 3046 const double distance = Center.NormSquared(); 3047 if ((ClosestLine == NULL) || (distance < MinDistance)) { 3048 // additionally calculate intersection on line (whether it's on the line section or not) 3049 helper.CopyVector(x); 3050 helper.SubtractVector((LineRunner->second)->endpoints[0]->node->node); 3051 helper.SubtractVector(&Center); 3052 const double lengthA = helper.ScalarProduct(&BaseLine); 3053 helper.CopyVector(x); 3054 helper.SubtractVector((LineRunner->second)->endpoints[1]->node->node); 3055 helper.SubtractVector(&Center); 3056 const double lengthB = helper.ScalarProduct(&BaseLine); 3057 if (lengthB*lengthA < 0) { // if have different sign 3058 ClosestLine = LineRunner->second; 3059 MinDistance = distance; 3060 Log() << Verbose(1) << "ACCEPT: New closest line is " << *ClosestLine << " with projected distance " << MinDistance << "." << endl; 3061 } else { 3062 Log() << Verbose(1) << "REJECT: Intersection is outside of the line section: " << lengthA << " and " << lengthB << "." << endl; 3063 } 3064 } else { 3065 Log() << Verbose(1) << "REJECT: Point is too further away than present line: " << distance << " >> " << MinDistance << "." << endl; 3066 } 3067 } 3068 } 3069 // check whether closest line is "too close" :), then it's inside 3070 if (ClosestLine == NULL) { 3001 3071 Log() << Verbose(0) << "Is the only point, no one else is closeby." << endl; 3002 3072 return NULL; 3003 3073 } 3004 if (trianglePoints[0]->node->DistanceSquared(x) < MYEPSILON) { 3005 Log() << Verbose(1) << "Point is right on a tesselation point, no nearest triangle." << endl; 3006 PointMap::const_iterator PointRunner = PointsOnBoundary.find(trianglePoints[0]->nr); 3007 triangles = new list<BoundaryTriangleSet*>; 3008 if (PointRunner != PointsOnBoundary.end()) { 3009 for(LineMap::iterator LineRunner = PointRunner->second->lines.begin(); LineRunner != PointRunner->second->lines.end(); LineRunner++) 3010 for(TriangleMap::iterator TriangleRunner = LineRunner->second->triangles.begin(); TriangleRunner != LineRunner->second->triangles.end(); TriangleRunner++) 3011 triangles->push_back(TriangleRunner->second); 3012 triangles->sort(); 3013 triangles->unique(); 3014 } else { 3015 PointRunner = PointsOnBoundary.find(SecondPoint->nr); 3016 trianglePoints[0] = SecondPoint; 3017 if (PointRunner != PointsOnBoundary.end()) { 3018 for(LineMap::iterator LineRunner = PointRunner->second->lines.begin(); LineRunner != PointRunner->second->lines.end(); LineRunner++) 3019 for(TriangleMap::iterator TriangleRunner = LineRunner->second->triangles.begin(); TriangleRunner != LineRunner->second->triangles.end(); TriangleRunner++) 3020 triangles->push_back(TriangleRunner->second); 3021 triangles->sort(); 3022 triangles->unique(); 3023 } else { 3024 eLog() << Verbose(1) << "I cannot find a boundary point to the tessel point " << *trianglePoints[0] << "." << endl; 3025 return NULL; 3026 } 3027 } 3028 } else { 3029 set<TesselPoint*> *connectedPoints = GetAllConnectedPoints(trianglePoints[0]); 3030 TesselPointList *connectedClosestPoints = GetCircleOfSetOfPoints(connectedPoints, trianglePoints[0], x); 3031 delete(connectedPoints); 3032 if (connectedClosestPoints != NULL) { 3033 trianglePoints[1] = connectedClosestPoints->front(); 3034 trianglePoints[2] = connectedClosestPoints->back(); 3035 for (int i=0;i<3;i++) { 3036 if (trianglePoints[i] == NULL) { 3037 eLog() << Verbose(1) << "IsInnerPoint encounters serious error, point " << i << " not found." << endl; 3038 } 3039 //Log() << Verbose(1) << "List of triangle points:" << endl; 3040 //Log() << Verbose(2) << *trianglePoints[i] << endl; 3041 } 3042 3043 triangles = FindTriangles(trianglePoints); 3044 Log() << Verbose(1) << "List of possible triangles:" << endl; 3045 for(list<BoundaryTriangleSet*>::iterator Runner = triangles->begin(); Runner != triangles->end(); Runner++) 3046 Log() << Verbose(2) << **Runner << endl; 3047 3048 delete(connectedClosestPoints); 3049 } else { 3050 triangles = NULL; 3051 eLog() << Verbose(2) << "There is no circle of connected points!" << endl; 3052 } 3053 } 3054 3055 if ((triangles == NULL) || (triangles->empty())) { 3056 eLog() << Verbose(1) << "There is no nearest triangle. Please check the tesselation structure."; 3057 delete(triangles); 3058 return NULL; 3059 } else 3060 return triangles; 3074 list<BoundaryTriangleSet*> *triangles = new list<BoundaryTriangleSet*>; 3075 for (TriangleMap::iterator Runner = ClosestLine->triangles.begin(); Runner != ClosestLine->triangles.end(); Runner++) { 3076 triangles->push_back(Runner->second); 3077 } 3078 return triangles; 3061 3079 }; 3062 3080 … … 3072 3090 class BoundaryTriangleSet *result = NULL; 3073 3091 list<BoundaryTriangleSet*> *triangles = FindClosestTrianglesToPoint(x, LC); 3092 list<BoundaryTriangleSet*> candidates; 3074 3093 Vector Center; 3075 3076 if (triangles == NULL) 3094 Vector helper; 3095 3096 if ((triangles == NULL) || (triangles->empty())) 3077 3097 return NULL; 3078 3098 3079 if (triangles->size() == 1) { // there is no degenerate case 3080 result = triangles->front(); 3081 Log() << Verbose(1) << "Normal Vector of this triangle is " << result->NormalVector << "." << endl; 3099 // reject all which are not closest 3100 double MinDistance = -1.; 3101 for (list<BoundaryTriangleSet*>::iterator Runner = triangles->begin(); Runner != triangles->end(); Runner++) { 3102 (*Runner)->GetCenter(&Center); 3103 helper.CopyVector(x); 3104 helper.SubtractVector(&Center); 3105 helper.ProjectOntoPlane(&(*Runner)->NormalVector); 3106 const double distance = helper.NormSquared(); 3107 if (fabs(distance - MinDistance) < MYEPSILON) { // degenerate case, keep both 3108 candidates.push_back(*Runner); 3109 } else if (distance < MinDistance) { 3110 candidates.clear(); 3111 candidates.push_back(*Runner); 3112 MinDistance = distance; 3113 } 3114 } 3115 delete(triangles); 3116 if (!candidates.empty()) { 3117 if (candidates.size() == 1) { // there is no degenerate case 3118 result = candidates.front(); 3119 Log() << Verbose(1) << "Normal Vector of this triangle is " << result->NormalVector << "." << endl; 3120 } else { 3121 result = candidates.front(); 3122 result->GetCenter(&Center); 3123 Center.SubtractVector(x); 3124 Log() << Verbose(1) << "Normal Vector of this front side is " << result->NormalVector << "." << endl; 3125 if (Center.ScalarProduct(&result->NormalVector) < 0) { 3126 result = candidates.back(); 3127 Log() << Verbose(1) << "Normal Vector of this back side is " << result->NormalVector << "." << endl; 3128 if (Center.ScalarProduct(&result->NormalVector) < 0) { 3129 eLog() << Verbose(1) << "Front and back side yield NormalVector in wrong direction!" << endl; 3130 } 3131 } 3132 } 3082 3133 } else { 3083 result = triangles->front(); 3084 result->GetCenter(&Center); 3085 Center.SubtractVector(x); 3086 Log() << Verbose(1) << "Normal Vector of this front side is " << result->NormalVector << "." << endl; 3087 if (Center.ScalarProduct(&result->NormalVector) < 0) { 3088 result = triangles->back(); 3089 Log() << Verbose(1) << "Normal Vector of this back side is " << result->NormalVector << "." << endl; 3090 if (Center.ScalarProduct(&result->NormalVector) < 0) { 3091 eLog() << Verbose(1) << "Front and back side yield NormalVector in wrong direction!" << endl; 3092 } 3093 } 3094 } 3095 delete(triangles); 3134 result = NULL; 3135 Log() << Verbose(0) << "No closest triangle found." << endl; 3136 } 3096 3137 return result; 3097 3138 }; … … 3101 3142 * @param point of which to check the position 3102 3143 * @param *LC LinkedCell structure 3144 * @param epsilon Distance of \a &Point to Center of triangle (of point outwards) is tested less against this value (standard: -MYEPSILON) 3103 3145 * 3104 3146 * @return true if the point is inside the tesselation structure, false otherwise 3105 3147 */ 3106 bool Tesselation::IsInnerPoint(const Vector &Point, const LinkedCell* const LC ) const3148 bool Tesselation::IsInnerPoint(const Vector &Point, const LinkedCell* const LC, const double epsilon) const 3107 3149 { 3108 3150 Info FunctionInfo(__func__); 3109 3151 class BoundaryTriangleSet *result = FindClosestTriangleToPoint(&Point, LC); 3110 3152 Vector Center; 3153 Vector helper; 3111 3154 3112 3155 if (result == NULL) {// is boundary point or only point in point cloud? 3113 3156 Log() << Verbose(1) << Point << " is the only point in vicinity." << endl; 3114 3157 return false; 3158 } else { 3159 Log() << Verbose(1) << "INFO: Closest triangle found is " << *result << "." << endl; 3115 3160 } 3116 3161 … … 3118 3163 Log() << Verbose(2) << "INFO: Central point of the triangle is " << Center << "." << endl; 3119 3164 Center.SubtractVector(&Point); 3120 Log() << Verbose(2) << "INFO: Vector from center to point to testis " << Center << "." << endl;3165 Log() << Verbose(2) << "INFO: Vector from point to test to center is " << Center << "." << endl; 3121 3166 if (Center.ScalarProduct(&result->NormalVector) > -MYEPSILON) { 3122 3167 Log() << Verbose(1) << Point << " is an inner point." << endl; 3123 3168 return true; 3124 3169 } else { 3170 for (int i=0;i<3;i++) { 3171 helper.CopyVector(result->endpoints[i]->node->node); 3172 helper.SubtractVector(&Point); 3173 if (Center.NormSquared() > helper.NormSquared()) 3174 Center.CopyVector(&helper); 3175 } 3176 if (Center.NormSquared() < epsilon*epsilon) { 3177 Log() << Verbose(1) << Point << " is inner point, being sufficiently close (wrt " << epsilon << ") to boundary." << endl; 3178 return true; 3179 } 3125 3180 Log() << Verbose(1) << Point << " is NOT an inner point." << endl; 3126 3181 return false; … … 3132 3187 * @param *Point of which to check the position 3133 3188 * @param *LC Linked Cell structure 3189 * @param epsilon Distance of \a &Point to Center of triangle is tested greater against this value (standard: -MYEPSILON) 3134 3190 * 3135 3191 * @return true if the point is inside the tesselation structure, false otherwise 3136 3192 */ 3137 bool Tesselation::IsInnerPoint(const TesselPoint * const Point, const LinkedCell* const LC ) const3138 { 3139 Info FunctionInfo(__func__); 3140 return IsInnerPoint(*(Point->node), LC );3193 bool Tesselation::IsInnerPoint(const TesselPoint * const Point, const LinkedCell* const LC, const double epsilon) const 3194 { 3195 Info FunctionInfo(__func__); 3196 return IsInnerPoint(*(Point->node), LC, epsilon); 3141 3197 } 3198 3199 /** 3200 * Finds the point which is second closest to the provided one. 3201 * 3202 * @param Point to which to find the second closest other point 3203 * @param linked cell structure 3204 * 3205 * @return point which is second closest to the provided one 3206 * @TODO Optimize me! These finds are unnecessary if we have a LC list of BoundaryPoints only! 3207 */ 3208 TesselPoint* Tesselation::FindSecondClosestBoundaryPoint(const Vector* Point, const LinkedCell* const LC) const 3209 { 3210 Info FunctionInfo(__func__); 3211 TesselPoint* closestPoint = NULL; 3212 TesselPoint* secondClosestPoint = NULL; 3213 double distance = 1e16; 3214 double secondDistance = 1e16; 3215 Vector helper; 3216 int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 3217 3218 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly 3219 for(int i=0;i<NDIM;i++) // store indices of this cell 3220 N[i] = LC->n[i]; 3221 Log() << Verbose(1) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl; 3222 3223 LC->GetNeighbourBounds(Nlower, Nupper); 3224 //Log() << Verbose(1) << endl; 3225 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 3226 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 3227 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 3228 const LinkedNodes *List = LC->GetCurrentCell(); 3229 //Log() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl; 3230 if (List != NULL) { 3231 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) { 3232 helper.CopyVector(Point); 3233 helper.SubtractVector((*Runner)->node); 3234 double currentNorm = helper. Norm(); 3235 if (PointsOnBoundary.find((*Runner)->nr) != PointsOnBoundary.end()) { 3236 if (currentNorm < distance) { 3237 // remember second point 3238 secondDistance = distance; 3239 secondClosestPoint = closestPoint; 3240 // mark down new closest point 3241 distance = currentNorm; 3242 closestPoint = (*Runner); 3243 //Log() << Verbose(2) << "INFO: New Second Nearest Neighbour is " << *secondClosestPoint << "." << endl; 3244 } 3245 } 3246 } 3247 } else { 3248 eLog() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," 3249 << LC->n[2] << " is invalid!" << endl; 3250 } 3251 } 3252 3253 return secondClosestPoint; 3254 }; 3255 3256 /** 3257 * Finds the point which is closest to the provided one. 3258 * 3259 * @param Point to which to find the closest other point 3260 * @param SecondPoint the second closest other point on return, NULL if none found 3261 * @param linked cell structure 3262 * 3263 * @return point which is closest to the provided one, NULL if none found 3264 * @TODO Optimize me! These finds are unnecessary if we have a LC list of BoundaryPoints only! 3265 */ 3266 TesselPoint* Tesselation::FindClosestBoundaryPoint(const Vector* Point, TesselPoint *&SecondPoint, const LinkedCell* const LC) const 3267 { 3268 Info FunctionInfo(__func__); 3269 TesselPoint* closestPoint = NULL; 3270 SecondPoint = NULL; 3271 double distance = 1e16; 3272 double secondDistance = 1e16; 3273 Vector helper; 3274 int N[NDIM], Nlower[NDIM], Nupper[NDIM]; 3275 3276 LC->SetIndexToVector(Point); // ignore status as we calculate bounds below sensibly 3277 for(int i=0;i<NDIM;i++) // store indices of this cell 3278 N[i] = LC->n[i]; 3279 Log() << Verbose(1) << "INFO: Center cell is " << N[0] << ", " << N[1] << ", " << N[2] << " with No. " << LC->index << "." << endl; 3280 3281 LC->GetNeighbourBounds(Nlower, Nupper); 3282 //Log() << Verbose(1) << endl; 3283 for (LC->n[0] = Nlower[0]; LC->n[0] <= Nupper[0]; LC->n[0]++) 3284 for (LC->n[1] = Nlower[1]; LC->n[1] <= Nupper[1]; LC->n[1]++) 3285 for (LC->n[2] = Nlower[2]; LC->n[2] <= Nupper[2]; LC->n[2]++) { 3286 const LinkedNodes *List = LC->GetCurrentCell(); 3287 //Log() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << endl; 3288 if (List != NULL) { 3289 for (LinkedNodes::const_iterator Runner = List->begin(); Runner != List->end(); Runner++) { 3290 helper.CopyVector(Point); 3291 helper.SubtractVector((*Runner)->node); 3292 double currentNorm = helper.NormSquared(); 3293 if (PointsOnBoundary.find((*Runner)->nr) != PointsOnBoundary.end()) { 3294 if (currentNorm < distance) { 3295 secondDistance = distance; 3296 SecondPoint = closestPoint; 3297 distance = currentNorm; 3298 closestPoint = (*Runner); 3299 //Log() << Verbose(1) << "INFO: New Nearest Neighbour is " << *closestPoint << "." << endl; 3300 } else if (currentNorm < secondDistance) { 3301 secondDistance = currentNorm; 3302 SecondPoint = (*Runner); 3303 //Log() << Verbose(1) << "INFO: New Second Nearest Neighbour is " << *SecondPoint << "." << endl; 3304 } 3305 } 3306 } 3307 } else { 3308 eLog() << Verbose(1) << "The current cell " << LC->n[0] << "," << LC->n[1] << "," << LC->n[2] << " is invalid!" << endl; 3309 } 3310 } 3311 // output 3312 if ((closestPoint != NULL) && (SecondPoint != NULL)) { 3313 Log() << Verbose(1) << "Closest point is " << *closestPoint << " and second closest is " << *SecondPoint << "." << endl; 3314 } else if (closestPoint != NULL) { 3315 Log() << Verbose(1) << "Closest point is " << *closestPoint << " and second closest is " << SecondPoint << "." << endl; 3316 } else { 3317 Log() << Verbose(1) << "No closest point has been found, only " << closestPoint << " and " << SecondPoint << "." << endl; 3318 } 3319 return closestPoint; 3320 }; 3321 3142 3322 3143 3323 /** Gets all points connected to the provided point by triangulation lines. … … 3191 3371 } 3192 3372 3193 if (connectedPoints-> size() == 0) { // if have not found any points3373 if (connectedPoints->empty()) { // if have not found any points 3194 3374 eLog() << Verbose(1) << "We have not found any connected points to " << *Point<< "." << endl; 3195 3375 return NULL; … … 3212 3392 * @return list of the all points linked to the provided one 3213 3393 */ 3394 list<TesselPoint*> * Tesselation::GetCircleOfConnectedTriangles(set<TesselPoint*> *SetOfNeighbours, const TesselPoint* const Point, const Vector * const Reference) const 3395 { 3396 Info FunctionInfo(__func__); 3397 map<double, TesselPoint*> anglesOfPoints; 3398 list<TesselPoint*> *connectedCircle = new list<TesselPoint*>; 3399 Vector PlaneNormal; 3400 Vector AngleZero; 3401 Vector OrthogonalVector; 3402 Vector helper; 3403 const TesselPoint * const TrianglePoints[3] = {Point, NULL, NULL}; 3404 list<BoundaryTriangleSet*> *triangles = NULL; 3405 3406 if (SetOfNeighbours == NULL) { 3407 eLog() << Verbose(2) << "Could not find any connected points!" << endl; 3408 delete(connectedCircle); 3409 return NULL; 3410 } 3411 3412 // calculate central point 3413 triangles = FindTriangles(TrianglePoints); 3414 if ((triangles != NULL) && (!triangles->empty())) { 3415 for (list<BoundaryTriangleSet*>::iterator Runner = triangles->begin(); Runner != triangles->end(); Runner++) 3416 PlaneNormal.AddVector(&(*Runner)->NormalVector); 3417 } else { 3418 eLog() << Verbose(0) << "Could not find any triangles for point " << *Point << "." << endl; 3419 performCriticalExit(); 3420 } 3421 PlaneNormal.Scale(1.0/triangles->size()); 3422 Log() << Verbose(1) << "INFO: Calculated PlaneNormal of all circle points is " << PlaneNormal << "." << endl; 3423 PlaneNormal.Normalize(); 3424 3425 // construct one orthogonal vector 3426 if (Reference != NULL) { 3427 AngleZero.CopyVector(Reference); 3428 AngleZero.SubtractVector(Point->node); 3429 AngleZero.ProjectOntoPlane(&PlaneNormal); 3430 } 3431 if ((Reference == NULL) || (AngleZero.NormSquared() < MYEPSILON )) { 3432 Log() << Verbose(1) << "Using alternatively " << *(*SetOfNeighbours->begin())->node << " as angle 0 referencer." << endl; 3433 AngleZero.CopyVector((*SetOfNeighbours->begin())->node); 3434 AngleZero.SubtractVector(Point->node); 3435 AngleZero.ProjectOntoPlane(&PlaneNormal); 3436 if (AngleZero.NormSquared() < MYEPSILON) { 3437 eLog() << Verbose(0) << "CRITIAL: AngleZero is 0 even with alternative reference. The algorithm has to be changed here!" << endl; 3438 performCriticalExit(); 3439 } 3440 } 3441 Log() << Verbose(1) << "INFO: Reference vector on this plane representing angle 0 is " << AngleZero << "." << endl; 3442 if (AngleZero.NormSquared() > MYEPSILON) 3443 OrthogonalVector.MakeNormalVector(&PlaneNormal, &AngleZero); 3444 else 3445 OrthogonalVector.MakeNormalVector(&PlaneNormal); 3446 Log() << Verbose(1) << "INFO: OrthogonalVector on plane is " << OrthogonalVector << "." << endl; 3447 3448 // go through all connected points and calculate angle 3449 for (set<TesselPoint*>::iterator listRunner = SetOfNeighbours->begin(); listRunner != SetOfNeighbours->end(); listRunner++) { 3450 helper.CopyVector((*listRunner)->node); 3451 helper.SubtractVector(Point->node); 3452 helper.ProjectOntoPlane(&PlaneNormal); 3453 double angle = GetAngle(helper, AngleZero, OrthogonalVector); 3454 Log() << Verbose(0) << "INFO: Calculated angle is " << angle << " for point " << **listRunner << "." << endl; 3455 anglesOfPoints.insert(pair<double, TesselPoint*>(angle, (*listRunner))); 3456 } 3457 3458 for(map<double, TesselPoint*>::iterator AngleRunner = anglesOfPoints.begin(); AngleRunner != anglesOfPoints.end(); AngleRunner++) { 3459 connectedCircle->push_back(AngleRunner->second); 3460 } 3461 3462 return connectedCircle; 3463 } 3464 3465 /** Gets all points connected to the provided point by triangulation lines, ordered such that we have the circle round the point. 3466 * Maps them down onto the plane designated by the axis \a *Point and \a *Reference. The center of all points 3467 * connected in the tesselation to \a *Point is mapped to spherical coordinates with the zero angle being given 3468 * by the mapped down \a *Reference. Hence, the biggest and the smallest angles are those of the two shanks of the 3469 * triangle we are looking for. 3470 * 3471 * @param *out output stream for debugging 3472 * @param *SetOfNeighbours all points for which the angle should be calculated 3473 * @param *Point of which get all connected points 3474 * @param *Reference Reference vector for zero angle or NULL for no preference 3475 * @return list of the all points linked to the provided one 3476 */ 3214 3477 list<TesselPoint*> * Tesselation::GetCircleOfSetOfPoints(set<TesselPoint*> *SetOfNeighbours, const TesselPoint* const Point, const Vector * const Reference) const 3215 3478 { 3216 3479 Info FunctionInfo(__func__); 3217 3480 map<double, TesselPoint*> anglesOfPoints; 3218 3481 list<TesselPoint*> *connectedCircle = new list<TesselPoint*>; … … 3715 3978 * Finds triangles belonging to the three provided points. 3716 3979 * 3717 * @param *Points[3] list, is expected to contain three points 3980 * @param *Points[3] list, is expected to contain three points (NULL means wildcard) 3718 3981 * 3719 3982 * @return triangles which belong to the provided points, will be empty if there are none, … … 3727 3990 TriangleMap::const_iterator FindTriangle; 3728 3991 class BoundaryPointSet *TrianglePoints[3]; 3992 size_t NoOfWildcards = 0; 3729 3993 3730 3994 for (int i = 0; i < 3; i++) { 3731 PointMap::const_iterator FindPoint = PointsOnBoundary.find(Points[i]->nr);3732 if (FindPoint != PointsOnBoundary.end()) {3733 TrianglePoints[i] = FindPoint->second;3995 if (Points[i] == NULL) { 3996 NoOfWildcards++; 3997 TrianglePoints[i] = NULL; 3734 3998 } else { 3735 TrianglePoints[i] = NULL; 3736 } 3737 } 3738 3739 // checks lines between the points in the Points for their adjacent triangles 3740 for (int i = 0; i < 3; i++) { 3741 if (TrianglePoints[i] != NULL) { 3742 for (int j = i+1; j < 3; j++) { 3743 if (TrianglePoints[j] != NULL) { 3744 for (FindLine = TrianglePoints[i]->lines.find(TrianglePoints[j]->node->nr); // is a multimap! 3745 (FindLine != TrianglePoints[i]->lines.end()) && (FindLine->first == TrianglePoints[j]->node->nr); 3746 FindLine++) { 3747 for (FindTriangle = FindLine->second->triangles.begin(); 3748 FindTriangle != FindLine->second->triangles.end(); 3749 FindTriangle++) { 3750 if (FindTriangle->second->IsPresentTupel(TrianglePoints)) { 3751 result->push_back(FindTriangle->second); 3999 PointMap::const_iterator FindPoint = PointsOnBoundary.find(Points[i]->nr); 4000 if (FindPoint != PointsOnBoundary.end()) { 4001 TrianglePoints[i] = FindPoint->second; 4002 } else { 4003 TrianglePoints[i] = NULL; 4004 } 4005 } 4006 } 4007 4008 switch (NoOfWildcards) { 4009 case 0: // checks lines between the points in the Points for their adjacent triangles 4010 for (int i = 0; i < 3; i++) { 4011 if (TrianglePoints[i] != NULL) { 4012 for (int j = i+1; j < 3; j++) { 4013 if (TrianglePoints[j] != NULL) { 4014 for (FindLine = TrianglePoints[i]->lines.find(TrianglePoints[j]->node->nr); // is a multimap! 4015 (FindLine != TrianglePoints[i]->lines.end()) && (FindLine->first == TrianglePoints[j]->node->nr); 4016 FindLine++) { 4017 for (FindTriangle = FindLine->second->triangles.begin(); 4018 FindTriangle != FindLine->second->triangles.end(); 4019 FindTriangle++) { 4020 if (FindTriangle->second->IsPresentTupel(TrianglePoints)) { 4021 result->push_back(FindTriangle->second); 4022 } 4023 } 3752 4024 } 4025 // Is it sufficient to consider one of the triangle lines for this. 4026 return result; 3753 4027 } 3754 4028 } 3755 // Is it sufficient to consider one of the triangle lines for this.3756 return result;3757 4029 } 3758 4030 } 3759 } 4031 break; 4032 case 1: // copy all triangles of the respective line 4033 { 4034 int i=0; 4035 for (; i < 3; i++) 4036 if (TrianglePoints[i] == NULL) 4037 break; 4038 for (FindLine = TrianglePoints[(i+1)%3]->lines.find(TrianglePoints[(i+2)%3]->node->nr); // is a multimap! 4039 (FindLine != TrianglePoints[(i+1)%3]->lines.end()) && (FindLine->first == TrianglePoints[(i+2)%3]->node->nr); 4040 FindLine++) { 4041 for (FindTriangle = FindLine->second->triangles.begin(); 4042 FindTriangle != FindLine->second->triangles.end(); 4043 FindTriangle++) { 4044 if (FindTriangle->second->IsPresentTupel(TrianglePoints)) { 4045 result->push_back(FindTriangle->second); 4046 } 4047 } 4048 } 4049 break; 4050 } 4051 case 2: // copy all triangles of the respective point 4052 { 4053 int i=0; 4054 for (; i < 3; i++) 4055 if (TrianglePoints[i] != NULL) 4056 break; 4057 for (LineMap::const_iterator line = TrianglePoints[i]->lines.begin(); line != TrianglePoints[i]->lines.end(); line++) 4058 for (TriangleMap::const_iterator triangle = line->second->triangles.begin(); triangle != line->second->triangles.end(); triangle++) 4059 result->push_back(triangle->second); 4060 result->sort(); 4061 result->unique(); 4062 break; 4063 } 4064 case 3: // copy all triangles 4065 { 4066 for (TriangleMap::const_iterator triangle = TrianglesOnBoundary.begin(); triangle != TrianglesOnBoundary.end(); triangle++) 4067 result->push_back(triangle->second); 4068 break; 4069 } 4070 default: 4071 eLog() << Verbose(0) << "Number of wildcards is greater than 3, cannot happen!" << endl; 4072 performCriticalExit(); 4073 break; 3760 4074 } 3761 4075 … … 3982 4296 // find nearest boundary point 3983 4297 class TesselPoint *BackupPoint = NULL; 3984 class TesselPoint *NearestPoint = FindClosest Point(point->node, BackupPoint, LC);4298 class TesselPoint *NearestPoint = FindClosestTesselPoint(point->node, BackupPoint, LC); 3985 4299 class BoundaryPointSet *NearestBoundaryPoint = NULL; 3986 4300 PointMap::iterator PointRunner; -
src/tesselation.hpp
r3930eb r71b20e 226 226 virtual TesselPoint *GetPoint() const { return NULL; }; 227 227 virtual TesselPoint *GetTerminalPoint() const { return NULL; }; 228 virtual int GetMaxId() const { return 0; }; 228 229 virtual void GoToNext() const {}; 229 230 virtual void GoToPrevious() const {}; … … 301 302 list<list<TesselPoint*> *> * GetClosedPathsOfConnectedPoints(const TesselPoint* const Point) const; 302 303 list<TesselPoint*> * GetCircleOfSetOfPoints(set<TesselPoint*> *SetOfNeighbours, const TesselPoint* const Point, const Vector * const Reference = NULL) const; 304 list<TesselPoint*> * GetCircleOfConnectedTriangles(set<TesselPoint*> *SetOfNeighbours, const TesselPoint* const Point, const Vector * const Reference) const; 303 305 class BoundaryPointSet *GetCommonEndpoint(const BoundaryLineSet * line1, const BoundaryLineSet * line2) const; 304 306 list<BoundaryTriangleSet*> *FindTriangles(const TesselPoint* const Points[3]) const; 305 307 list<BoundaryTriangleSet*> * FindClosestTrianglesToPoint(const Vector *x, const LinkedCell* LC) const; 306 308 class BoundaryTriangleSet * FindClosestTriangleToPoint(const Vector *x, const LinkedCell* LC) const; 307 bool IsInnerPoint(const Vector &Point, const LinkedCell* const LC ) const;308 bool IsInnerPoint(const TesselPoint * const Point, const LinkedCell* const LC ) const;309 bool IsInnerPoint(const Vector &Point, const LinkedCell* const LC, const double epsilon = -MYEPSILON) const; 310 bool IsInnerPoint(const TesselPoint * const Point, const LinkedCell* const LC, const double epsilon = -MYEPSILON) const; 309 311 bool AddBoundaryPoint(TesselPoint * Walker, const int n); 312 TesselPoint* FindSecondClosestBoundaryPoint(const Vector* Point, const LinkedCell* const LC) const; 313 TesselPoint* FindClosestBoundaryPoint(const Vector* Point, TesselPoint *&SecondPoint, const LinkedCell* const LC) const; 310 314 311 315 // print for debugging -
src/tesselationhelpers.cpp
r3930eb r71b20e 558 558 * @return point which is second closest to the provided one 559 559 */ 560 TesselPoint* FindSecondClosest Point(const Vector* Point, const LinkedCell* const LC)560 TesselPoint* FindSecondClosestTesselPoint(const Vector* Point, const LinkedCell* const LC) 561 561 { 562 562 Info FunctionInfo(__func__); … … 613 613 * @return point which is closest to the provided one, NULL if none found 614 614 */ 615 TesselPoint* FindClosest Point(const Vector* Point, TesselPoint *&SecondPoint, const LinkedCell* const LC)615 TesselPoint* FindClosestTesselPoint(const Vector* Point, TesselPoint *&SecondPoint, const LinkedCell* const LC) 616 616 { 617 617 Info FunctionInfo(__func__); … … 639 639 helper.CopyVector(Point); 640 640 helper.SubtractVector((*Runner)->node); 641 double currentNorm = helper. Norm();641 double currentNorm = helper.NormSquared(); 642 642 if (currentNorm < distance) { 643 643 secondDistance = distance; … … 809 809 TesselPoint *Walker = NULL; 810 810 int i; 811 Vector *center = cloud->GetCenter();811 Vector *center = new Vector(); //cloud->GetCenter(); 812 812 if (rasterfile != NULL) { 813 813 //Log() << Verbose(1) << "Writing Raster3D file ... "; … … 866 866 } 867 867 *tecplot << "\", N=" << TesselStruct->PointsOnBoundary.size() << ", E=" << TesselStruct->TrianglesOnBoundary.size() << ", DATAPACKING=POINT, ZONETYPE=FETRIANGLE" << endl; 868 int i=0; 869 for (cloud->GoToFirst(); !cloud->IsEnd(); cloud->GoToNext(), i++); 868 int i=cloud->GetMaxId(); 870 869 int *LookupList = new int[i]; 871 870 for (cloud->GoToFirst(), i=0; !cloud->IsEnd(); cloud->GoToNext(), i++) -
src/tesselationhelpers.hpp
r3930eb r71b20e 59 59 bool CheckLineCriteriaForDegeneratedTriangle(const BoundaryPointSet * const nodes[3]); 60 60 bool SortCandidates(const CandidateForTesselation* candidate1, const CandidateForTesselation *candidate2); 61 TesselPoint* FindClosest Point(const Vector* Point, TesselPoint *&SecondPoint, const LinkedCell* const LC);62 TesselPoint* FindSecondClosest Point(const Vector*, const LinkedCell* const LC);61 TesselPoint* FindClosestTesselPoint(const Vector* Point, TesselPoint *&SecondPoint, const LinkedCell* const LC); 62 TesselPoint* FindSecondClosestTesselPoint(const Vector*, const LinkedCell* const LC); 63 63 Vector * GetClosestPointBetweenLine(const BoundaryLineSet * const Base, const BoundaryLineSet * const OtherBase); 64 64
Note:
See TracChangeset
for help on using the changeset viewer.