From 00ba9c1476b54ebd2704f3d775ae88ab00cf0b2f Mon Sep 17 00:00:00 2001
From: Dmitri Naumov <dmitri.naumov@ufz.de>
Date: Tue, 19 Feb 2019 19:50:53 +0100
Subject: [PATCH] [App/U] Refactor MeshToRaster utility.

---
 .../Utils/FileConverter/MeshToRaster.cpp      | 119 ++++++++----------
 1 file changed, 52 insertions(+), 67 deletions(-)

diff --git a/Applications/Utils/FileConverter/MeshToRaster.cpp b/Applications/Utils/FileConverter/MeshToRaster.cpp
index de4db243174..cf97d4a7810 100644
--- a/Applications/Utils/FileConverter/MeshToRaster.cpp
+++ b/Applications/Utils/FileConverter/MeshToRaster.cpp
@@ -13,8 +13,7 @@
 
 #include <tclap/CmdLine.h>
 
-#include <Applications/ApplicationsLib/LogogSetup.h>
-
+#include "Applications/ApplicationsLib/LogogSetup.h"
 #include "BaseLib/BuildInfo.h"
 #include "GeoLib/AABB.h"
 #include "GeoLib/AnalyticalGeometry.h"
@@ -25,10 +24,10 @@
 #include "MeshLib/MeshSearch/MeshElementGrid.h"
 #include "MeshLib/Node.h"
 
-/// Returns the index of the element the given node is located in when projected
-/// onto a mesh.
-std::size_t getProjectedElementIndex(
-    std::vector<const MeshLib::Element*> const& elems,
+/// Returns the element in which the given node is located when projected onto a
+/// mesh, or nullptr if no such element was found.
+static MeshLib::Element const* getProjectedElement(
+    std::vector<const MeshLib::Element*> const& elements,
     MeshLib::Node const& node)
 {
     auto is_right_of = [&node](MeshLib::Node const& a, MeshLib::Node const& b) {
@@ -36,59 +35,44 @@ std::size_t getProjectedElementIndex(
                GeoLib::Orientation::CW;
     };
 
-    std::size_t const n_elems = elems.size();
-    for (std::size_t i = 0; i < n_elems; ++i)
+    for (auto const* e : elements)
     {
-        if (elems[i]->getGeomType() == MeshLib::MeshElemType::LINE)
-        {
-            continue;
-        }
-        auto const& a = *elems[i]->getNode(0);
-        auto const& b = *elems[i]->getNode(1);
-        if (is_right_of(a, b))
-        {
-            continue;
-        }
-        auto const& c = *elems[i]->getNode(2);
-        if (is_right_of(b, c))
+        auto const* nodes = e->getNodes();
+        if (e->getGeomType() == MeshLib::MeshElemType::TRIANGLE)
         {
-            continue;
-        }
-        if (elems[i]->getGeomType() == MeshLib::MeshElemType::TRIANGLE)
-        {
-            if (is_right_of(c, a))
+            auto const& a = *nodes[0];
+            auto const& b = *nodes[1];
+            auto const& c = *nodes[2];
+            if (!is_right_of(a, b) && !is_right_of(b, c) && !is_right_of(c, a))
             {
-                continue;
+                return e;
             }
         }
-        if (elems[i]->getGeomType() == MeshLib::MeshElemType::QUAD)
+        else if (e->getGeomType() == MeshLib::MeshElemType::QUAD)
         {
-            auto const& d = *elems[i]->getNode(3);
-            if (is_right_of(c, d))
-            {
-                continue;
-            }
-            if (is_right_of(d, a))
+            auto const& a = *nodes[0];
+            auto const& b = *nodes[1];
+            auto const& c = *nodes[2];
+            auto const& d = *nodes[3];
+            if (!is_right_of(a, b) && !is_right_of(b, c) &&
+                !is_right_of(c, d) && !is_right_of(d, a))
             {
-                continue;
+                return e;
             }
         }
-        return elems[i]->getID();
     }
-    return std::numeric_limits<size_t>::max();
+    return nullptr;
 }
 
 /// Returns the z-coordinate of a point projected onto the plane defined by a
 /// mesh element.
-double getElevation(MeshLib::Element const& elem, MeshLib::Node const& node)
+static double getElevation(MeshLib::Element const& element,
+                           MeshLib::Node const& node)
 {
+    MathLib::Vector3 const v = node - *element.getNode(0);
     MathLib::Vector3 const n =
-        MeshLib::FaceRule::getSurfaceNormal(&elem).getNormalizedVector();
-    MeshLib::Node const& orig = *elem.getNode(0);
-    MathLib::Point3d const v{
-        {node[0] - orig[0], node[1] - orig[1], node[2] - orig[2]}};
-    double const dist = n[0] * v[0] + n[1] * v[1] + n[2] * v[2];
-    return node[2] - dist * n[2];
+        MeshLib::FaceRule::getSurfaceNormal(&element).getNormalizedVector();
+    return node[2] - scalarProduct(n, v) * n[2];
 }
 
 int main(int argc, char* argv[])
@@ -143,17 +127,18 @@ int main(int argc, char* argv[])
     GeoLib::AABB const bounding_box(nodes_vec.begin(), nodes_vec.end());
     MathLib::Point3d const& min(bounding_box.getMinPoint());
     MathLib::Point3d const& max(bounding_box.getMaxPoint());
-    std::size_t const n_cols =
+    auto const n_cols =
         static_cast<std::size_t>(std::ceil((max[0] - min[0]) / cellsize));
-    std::size_t const n_rows =
+    auto const n_rows =
         static_cast<std::size_t>(std::ceil((max[1] - min[1]) / cellsize));
+    double const half_cell = cellsize / 2.0;
 
     // raster header
     std::ofstream out(output_arg.getValue());
     out << "ncols         " << n_cols + 1 << "\n";
     out << "nrows         " << n_rows + 1 << "\n";
-    out << std::fixed << "xllcorner     " << (min[0] - cellsize / 2.0) << "\n";
-    out << std::fixed << "yllcorner     " << (min[1] - cellsize / 2.0) << "\n";
+    out << std::fixed << "xllcorner     " << (min[0] - half_cell) << "\n";
+    out << std::fixed << "yllcorner     " << (min[1] - half_cell) << "\n";
     out << std::fixed << "cellsize      " << cellsize << "\n";
     out << "NODATA_value  "
         << "-9999\n";
@@ -162,26 +147,26 @@ int main(int argc, char* argv[])
     MeshLib::MeshElementGrid const grid(*mesh);
     double const max_edge(mesh->getMaxEdgeLength() + cellsize);
 
-    // pixel values
-    double x = min[0];
-    double y = max[1];
-    double const half_cell = cellsize / 2.0;
     for (std::size_t j = 0; j <= n_rows; ++j)
     {
+        double const y = max[1] - j * cellsize;
         for (std::size_t i = 0; i <= n_cols; ++i)
         {
+            // pixel values
+            double const x = min[0] + i * cellsize;
             MeshLib::Node const node(x, y, 0);
             MathLib::Point3d min_vol{{x - max_edge, y - max_edge,
                                       -std::numeric_limits<double>::max()}};
             MathLib::Point3d max_vol{{x + max_edge, y + max_edge,
                                       std::numeric_limits<double>::max()}};
-            std::vector<const MeshLib::Element*> const elems =
+            std::vector<const MeshLib::Element*> const& elems =
                 grid.getElementsInVolume(min_vol, max_vol);
-            std::size_t const elem_idx = getProjectedElementIndex(elems, node);
+            auto const* element = getProjectedElement(elems, node);
             // centre of the pixel is located within a mesh element
-            if (elem_idx != std::numeric_limits<std::size_t>::max())
-                out << getElevation(*(mesh->getElement(elem_idx)), node) << " ";
-            // centre of the pixel isn't located within a mesh element
+            if (element != nullptr)
+            {
+                out << getElevation(*element, node) << " ";
+            }
             else
             {
                 std::array<double, 4> const x_off{
@@ -190,31 +175,31 @@ int main(int argc, char* argv[])
                     {-half_cell, -half_cell, half_cell, half_cell}};
                 double sum(0);
                 std::size_t nonzero_count(0);
-                // test for all of the pixel's corner if any are within an
+                // test all of the pixel's corners if there are any within an
                 // element
                 for (std::size_t i = 0; i < 4; ++i)
                 {
                     MeshLib::Node const node(x + x_off[i], y + y_off[i], 0);
-                    std::size_t const corner_idx =
-                        getProjectedElementIndex(elems, node);
-                    if (corner_idx != std::numeric_limits<std::size_t>::max())
+                    auto const* corner_element =
+                        getProjectedElement(elems, node);
+                    if (corner_element != nullptr)
                     {
-                        sum +=
-                            getElevation(*(mesh->getElement(corner_idx)), node);
+                        sum += getElevation(*corner_element, node);
                         nonzero_count++;
                     }
                 }
-                // calculate pixel value as average of corner values
                 if (nonzero_count > 0)
+                {
+                    // calculate pixel value as average of corner values
                     out << sum / nonzero_count << " ";
-                // if none of the corners give a value, set pixel to NODATA
+                }
                 else
+                {
+                    // if none of the corners give a value, set pixel to NODATA
                     out << "-9999 ";
+                }
             }
-            x += cellsize;
         }
-        x = min[0];
-        y -= cellsize;
         out << "\n";
     }
     out.close();
-- 
GitLab