Changeset 1017 for cpp/frams/genetics/fS/part_distance_estimator.h
- Timestamp:
- 07/20/20 16:37:38 (3 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
cpp/frams/genetics/fS/part_distance_estimator.h
r1006 r1017 5 5 #ifndef _PART_DISTANCE_ESTIMATOR_H_ 6 6 #define _PART_DISTANCE_ESTIMATOR_H_ 7 8 #include "frams/model/geometry/meshbuilder.h" 7 9 8 10 class fS_Utils … … 44 46 class PartDistanceEstimator 45 47 { 46 /**47 * Used in finding the proper distance between the parts48 * distance between spheres / sphere radius49 * That default value can be changed in certain cases50 * */51 static constexpr float SPHERE_RELATIVE_DISTANCE = 0.5;52 /**53 * Used in finding the proper distance between the parts54 * The maximal allowed value for55 * maximal radius of the node / sphere radius56 */57 static const int MAX_DIAMETER_QUOTIENT = 30;58 /**59 * The tolerance of the value of distance between parts60 */61 static constexpr double SPHERE_DISTANCE_TOLERANCE = 0.96;62 48 63 static constexpr double SPHERE_SIZE_QUOTIENT = 0.25; 49 public: 50 static constexpr double PRECISION = 0.05; 51 static constexpr double RELATIVE_DENSITY = 5.0; 64 52 65 53 66 static bool isInsidePart(Part::Shape shape, const Pt3D &partRadii, const Pt3D ¢er, double sphereRadius)54 static Part *buildTemporaryPart(Part::Shape shape, const Pt3D &scale, const Pt3D &rotations) 67 55 { 68 if(sphereRadius >= fS_Utils::min3(partRadii)) 69 return true; // TODO Special case 70 Pt3D mostRemote = Pt3D(fabs(center.x), fabs(center.y), fabs(center.z)) + Pt3D(sphereRadius); 71 bool isInEllipsis; 72 73 bool result = false; 74 75 switch (shape) 76 { 77 case Part::Shape::SHAPE_CUBOID: 78 if(mostRemote.x <= partRadii.x && mostRemote.y <= partRadii.y && mostRemote.z <= partRadii.z) 79 result = true; 80 break; 81 case Part::Shape::SHAPE_CYLINDER: 82 isInEllipsis = pow(center.y / (partRadii.y - sphereRadius), 2) + pow(center.z / (partRadii.z - sphereRadius), 2) <= 1.0; 83 if (mostRemote.x <= partRadii.x && isInEllipsis) 84 result = true; 85 break; 86 case Part::Shape::SHAPE_ELLIPSOID: 87 if(pow(center.x / (partRadii.x - sphereRadius), 2) + pow(center.y / (partRadii.y - sphereRadius), 2) + pow(center.z / (partRadii.z - sphereRadius), 2) <= 1.0) 88 result = true; 89 break; 90 default: 91 logMessage("fS", "calculateVolume", LOG_ERROR, "Invalid part type"); 92 } 93 return result; 56 Part *tmpPart = new Part(shape); 57 tmpPart->scale = scale; 58 tmpPart->setRot(rotations); 59 return tmpPart; 94 60 } 95 61 96 public: 97 static vector<Pt3D> findSphereCenters(Part::Shape shape, double &sphereRadius, const Pt3D &radii, const Pt3D &rotations) 62 static vector <Pt3D> findSphereCenters(Part *part) 98 63 { 99 double sphereRelativeDistance = SPHERE_RELATIVE_DISTANCE;100 double minRadius = fS_Utils::min3(radii);101 if(minRadius <= 0)102 throw fS_Exception("Invalid part size in PartDistanceEstimator", 0); 103 double maxRadius = fS_Utils::max3(radii);104 sphereRadius = SPHERE_SIZE_QUOTIENT * minRadius;105 if (MAX_DIAMETER_QUOTIENT < maxRadius / sphereRadius)64 // Divide by maximal radius to avoid long computations 65 MeshBuilder::PartSurface surface(RELATIVE_DENSITY / fS_Utils::max3(part->scale)); 66 surface.initialize(part); 67 68 vector <Pt3D> centers; 69 Pt3D point; 70 while (surface.tryGetNext(point)) 106 71 { 107 // When max radius is much bigger than sphereRadius and there are to many spheresZ 108 sphereRelativeDistance = 1.0; // Make the spheres adjacent to speed up the computation 109 sphereRadius = maxRadius / MAX_DIAMETER_QUOTIENT; 110 } 111 else if(shape == Part::Shape::SHAPE_ELLIPSOID) 112 sphereRadius = minRadius; 113 114 double sphereDiameter = 2 * sphereRadius; 115 116 double radiiArr[3]{radii.x, radii.y, radii.z}; 117 vector<double> coordinates[3]; 118 for (int dim = 0; dim < 3; dim++) 119 { 120 double spaceForSphereCenters = 2 * radiiArr[dim] - sphereDiameter; 121 if (spaceForSphereCenters > 0) 122 { 123 int lastIndex = ceil(spaceForSphereCenters / (sphereDiameter * sphereRelativeDistance)); 124 for (int i = 0; i <= lastIndex; i++) 125 { 126 coordinates[dim].push_back(spaceForSphereCenters * (double(i) / lastIndex - 0.5)); 127 } 128 } 129 else 130 coordinates[dim].push_back(0.0); 131 } 132 133 vector<Pt3D> centers; 134 for (int xi = 0; xi < int(coordinates[0].size()); xi++) 135 { 136 for (int yi = 0; yi < int(coordinates[1].size()); yi++) 137 { 138 for (int zi = 0; zi < int(coordinates[2].size()); zi++) 139 { 140 Pt3D center = Pt3D(coordinates[0][xi], coordinates[1][yi], coordinates[2][zi]); 141 if (isInsidePart(shape, radii, center, sphereRadius)) 142 { 143 fS_Utils::rotateVector(center, rotations); 144 centers.push_back(center); 145 } 146 } 147 } 72 centers.push_back(point); 148 73 } 149 74 return centers; 150 75 } 151 76 152 static int isCollision(vector<Pt3D> ¢ersParent, vector<Pt3D> ¢ers, Pt3D &vectorBetweenParts, 153 double distanceThreshold) 77 static bool isCollision(Part *parentPart, vector <Pt3D> ¢ers, Pt3D &vectorBetweenParts) 154 78 { 155 double upperThresholdSq = distanceThreshold * distanceThreshold; 156 double lowerThresholdSq = pow(SPHERE_DISTANCE_TOLERANCE * distanceThreshold, 2); 157 double distanceSq; 158 double dx, dy, dz; 159 bool existsAdjacent = false; 160 Pt3D *tmpPoint; 161 for (int sc = 0; sc < int(centers.size()); sc++) 79 static double CBRT_3 = std::cbrt(3); 80 double maxParentReachSq = pow(CBRT_3 * fS_Utils::max3(parentPart->scale), 2); 81 for (int i = 0; i < int(centers.size()); i++) 162 82 { 163 Pt3D shiftedSphere = Pt3D(centers[sc]); 164 shiftedSphere += vectorBetweenParts; 165 for (int psc = 0; psc < int(centersParent.size()); psc++) 166 { 167 tmpPoint = ¢ersParent[psc]; 168 dx = shiftedSphere.x - tmpPoint->x; 169 dy = shiftedSphere.y - tmpPoint->y; 170 dz = shiftedSphere.z - tmpPoint->z; 171 distanceSq = dx * dx + dy * dy + dz * dz; 172 173 if (distanceSq <= upperThresholdSq) 174 { 175 if (distanceSq >= lowerThresholdSq) 176 existsAdjacent = true; 177 else 178 { 179 return COLLISION; 180 } 181 } 182 } 83 Pt3D shifted = centers[i] + vectorBetweenParts; 84 double distanceToCenterSq = shifted.x * shifted.x + shifted.y * shifted.y + shifted.z * shifted.z; 85 if (distanceToCenterSq <= maxParentReachSq && GeometryUtils::isPointInsidePart(shifted, parentPart)) 86 return true; 183 87 } 184 if (existsAdjacent) 185 return ADJACENT; 186 else 187 return DISJOINT; 88 return false; 188 89 } 189 90 }; … … 191 92 double Node::getDistance() 192 93 { 193 Pt3D size = calculateSize(); 194 Pt3D parentSize = parent->calculateSize(); // Here we are sure that parent is not nullptr 195 double parentSphereRadius, sphereRadius; 196 vector<Pt3D> centersParent = PartDistanceEstimator::findSphereCenters(parent->partType, parentSphereRadius, parentSize, parent->getRotation()); 197 vector<Pt3D> centers = PartDistanceEstimator::findSphereCenters(partType, sphereRadius, size, getRotation()); 94 Pt3D size; 95 calculateSize(size); 96 Pt3D parentSize; 97 parent->calculateSize(parentSize); // Here we are sure that parent is not nullptr 98 Part *tmpPart = PartDistanceEstimator::buildTemporaryPart(partType, size, getRotation()); 99 Part *parentTmpPart = PartDistanceEstimator::buildTemporaryPart(parent->partType, parentSize, parent->getRotation()); 198 100 199 double distanceThreshold = sphereRadius + parentSphereRadius; 101 vector <Pt3D> centers = PartDistanceEstimator::findSphereCenters(tmpPart); 102 200 103 double minDistance = 0.0; 201 104 double maxDistance = 2 * (fS_Utils::max3(parentSize) + fS_Utils::max3(size)); 202 105 double currentDistance = fS_Utils::avg(maxDistance, minDistance); 203 int result = -1; 204 int iterationNo = 0; 205 while (result != ADJACENT) 106 int collisionDetected = false; 107 while (maxDistance - minDistance > PartDistanceEstimator::PRECISION) 206 108 { 207 iterationNo++;208 109 Pt3D vectorBetweenParts = state->v * currentDistance; 209 result = PartDistanceEstimator::isCollision(centersParent, centers, vectorBetweenParts, distanceThreshold);110 collisionDetected = PartDistanceEstimator::isCollision(parentTmpPart, centers, vectorBetweenParts); 210 111 211 if (result == DISJOINT) 112 if (collisionDetected) 113 { 114 minDistance = currentDistance; 115 currentDistance = fS_Utils::avg(maxDistance, currentDistance); 116 } else 212 117 { 213 118 maxDistance = currentDistance; 214 119 currentDistance = fS_Utils::avg(currentDistance, minDistance); 215 } else if (result == COLLISION)216 {217 minDistance = currentDistance;218 currentDistance = fS_Utils::avg(maxDistance, currentDistance);219 120 } 220 221 if(maxDistance <= 0 || iterationNo > 1000)222 throw fS_Exception("Computing of distances between parts failed", 0);223 if (currentDistance > maxDistance)224 {225 throw fS_Exception("Internal error; the maximal distance between parts exceeded.", 0);226 }227 if (currentDistance < minDistance)228 throw fS_Exception("Internal error; the minimal distance between parts exceeded.", 0);229 230 121 } 231 122 delete tmpPart; 123 delete parentTmpPart; 232 124 return currentDistance; 233 125 }
Note: See TracChangeset
for help on using the changeset viewer.