Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Using C++ 20 and GLM library and using following definitions:
- 1. Tract is defined a line passing through set of 3D points
- 2. All tracts begin and end inside of 3D mesh which is defined as a set of 3D vertices (glm::vec3) and indices (uint32_t) where 3 indices define a single triangle of the mesh
- 3. Triangle closest to the tract starting point is defined as "start triangle" for that tract
- 4. Triangle closest to the tract ending point is defined as "end triangle" for that tract
- 5. There is a set of tracts defined in 1. available for use
- Implement the following algorithm:
- When user request a subset of tracts defined in 5., select and return the requested number of tracts, satisfying the following two criteria:
- CRITERIUM-A: Number of covered “start” and “end” triangles of the mesh defined in 2. shall be as big as possible (maximum mesh coverage)
- CRITERIUM-B: You shall maximally disperse the tracts so that set of tract starting and ending points covers the largest area (maximum dispersion), while satisfying CRITERIUM-A
- -------------------------------
- Including the necessary headers:
- ```cpp
- #include <iostream>
- #include <vector>
- #include <unordered_map>
- #include <algorithm>
- #include <glm/vec3.hpp>
- #include <glm/geometric.hpp>
- ```
- Defining Tract and Mesh structures:
- ```cpp
- struct Tract {
- std::vector<glm::vec3> points;
- glm::vec3 start() const { return points.front(); }
- glm::vec3 end() const { return points.back(); }
- };
- struct Mesh {
- std::vector<glm::vec3> vertices;
- std::vector<uint32_t> indices;
- };
- ```
- Function to find the closest triangle to a given point:
- ```cpp
- uint32_t findClosestTriangle(const Mesh& mesh, const glm::vec3& point) {
- uint32_t closestTriangle = 0;
- float minDistanceSqr = std::numeric_limits<float>::max();
- for (uint32_t i = 0; i < mesh.indices.size(); i += 3) {
- glm::vec3 a = mesh.vertices[mesh.indices[i]];
- glm::vec3 b = mesh.vertices[mesh.indices[i + 1]];
- glm::vec3 c = mesh.vertices[mesh.indices[i + 2]];
- glm::vec3 centroid = (a + b + c) / 3.0f;
- float distanceSqr = glm::distance2(point, centroid);
- if (distanceSqr < minDistanceSqr) {
- closestTriangle = i / 3;
- minDistanceSqr = distanceSqr;
- }
- }
- return closestTriangle;
- }
- ```
- Utility function to calculate the area covered by points:
- ```cpp
- float areaCoveredByPoints(const std::vector<glm::vec3>& points) {
- float area = 0;
- size_t n = points.size();
- for (size_t i = 0; i < n; i++) {
- glm::vec3 a = points[i];
- glm::vec3 b = points[(i + 1) % n];
- area += glm::cross(a, b).length();
- }
- return area / 2;
- }
- ```
- The main algorithm:
- ```cpp
- std::vector<Tract> selectTracts(const Mesh& mesh, const std::vector<Tract>& tracts, size_t requestedNumTracts) {
- if (requestedNumTracts >= tracts.size()) {
- return tracts;
- }
- struct TractStartEnd {
- uint32_t startTriangle;
- uint32_t endTriangle;
- };
- std::vector<TractStartEnd> tractStartEnds(tracts.size());
- for (size_t i = 0; i < tracts.size(); i++) {
- tractStartEnds[i] = {
- findClosestTriangle(mesh, tracts[i].start()),
- findClosestTriangle(mesh, tracts[i].end())
- };
- }
- std::vector<Tract> selectedTracts;
- selectedTracts.reserve(requestedNumTracts);
- std::unordered_map<uint32_t, size_t> coverage;
- auto updateCoverage = [&](const TractStartEnd& se) {
- coverage[se.startTriangle]++;
- coverage[se.endTriangle]++;
- };
- auto updateArea = [&]() {
- std::vector<glm::vec3> startPoints;
- std::vector<glm::vec3> endPoints;
- for (const Tract& tract : selectedTracts) {
- startPoints.push_back(tract.start());
- endPoints.push_back(tract.end());
- }
- return areaCoveredByPoints(startPoints) + areaCoveredByPoints(endPoints);
- };
- while (selectedTracts.size() < requestedNumTracts) {
- size_t maxCoverageIndex = 0;
- float maxCoverageArea = -1;
- for (size_t i = 0; i < tractStartEnds.size(); i++) {
- const TractStartEnd& cur = tractStartEnds[i];
- if (coverage[cur.startTriangle] > 0 || coverage[cur.endTriangle] > 0) {
- continue;
- }
- updateCoverage(cur);
- selectedTracts.push_back(tracts[i]);
- float curArea = updateArea();
- if (curArea > maxCoverageArea) {
- maxCoverageArea = curArea;
- maxCoverageIndex = i;
- }
- // Rollback
- coverage[cur.startTriangle]--;
- coverage[cur.endTriangle]--;
- selectedTracts.pop_back();
- }
- const TractStartEnd& selectedSE = tractStartEnds[maxCoverageIndex];
- updateCoverage(selectedSE);
- selectedTracts.push_back(tracts[maxCoverageIndex]);
- tractStartEnds.erase(tractStartEnds.begin() + maxCoverageIndex);
- tracts.erase(tracts.begin() + maxCoverageIndex);
- }
- return selectedTracts;
- }
- ```
- You can now use the `selectTracts` function to select tracts according to the given criteria:
- ```cpp
- Mesh mesh; // Populate the mesh with vertices and indices
- std::vector<Tract> tracts; // Populate the tracts with points
- size_t desiredNumOfTracts = 10;
- std::vector<Tract> selectedTracts = selectTracts(mesh, tracts, desiredNumOfTracts);
- // 'selectedTracts' now contains the selected subset of tracts.
- ```
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement