Program Listing for File Marsh_shading_iswr.cpp#
↰ Return to documentation for file (src/modules/Marsh_shading_iswr.cpp)
//
// Canadian Hydrological Model - The Canadian Hydrological Model (CHM) is a novel
// modular unstructured mesh based approach for hydrological modelling
// Copyright (C) 2018 Christopher Marsh
//
// This file is part of Canadian Hydrological Model.
//
// Canadian Hydrological Model is free software: you can redistribute it and/or
// modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Canadian Hydrological Model is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Canadian Hydrological Model. If not, see
// <http://www.gnu.org/licenses/>.
//
#include "Marsh_shading_iswr.hpp"
REGISTER_MODULE_CPP(Marsh_shading_iswr);
Marsh_shading_iswr::Marsh_shading_iswr(config_file cfg)
:module_base("Marsh_shading_iswr", parallel::domain, cfg)
{
depends("solar_az");
depends("solar_el");
provides("shadow");
provides("z_prime");
x_AABB = cfg.get<int>("x_AABB",10);
y_AABB = cfg.get<int>("y_AABB",10);
SPDLOG_DEBUG("Successfully instantiated module {}",this->ID);
}
void Marsh_shading_iswr::run(mesh& domain)
{
//compute the rotation of each vertex
// tbb::concurrent_vector<triangulation::Face_handle> rot_faces;
// rot_faces.grow_by(domain->size());
#pragma omp parallel for
for (size_t i = 0; i < domain->size_local_vertex(); i++)
{
auto vert = domain->vertex(i);
double A = (*vert->face())["solar_az"_s];
double E = (*vert->face())["solar_el"_s];
//euler rotation matrix K
arma::mat K;
// eqns(6) & (7) in Montero
double z0 = M_PI - A * M_PI / 180.0;
double q0 = M_PI / 2.0 - E * M_PI / 180.0;
K = {
{cos(z0) , sin(z0) , 0},
{-cos(q0) * sin(z0) , cos(q0) * cos(z0) , sin(q0)},
{sin(q0) * sin(z0) , -cos(z0) * sin(q0) , cos(q0)}
};
auto vf = vert->make_module_data<vertex_data>(ID);
arma::vec coord(3);
Point_3 p;
coord(0) = vert->point().x();
coord(1) = vert->point().y();
coord(2) = vert->point().z();
coord = K*coord;
p = Point_3(coord(0), coord(1), coord(2));
vf->prj_vertex = p;
vf->org_vertex = vert->point();
vert->set_point(vf->prj_vertex); //modify the underlying triangulation to reflect the rotated vertices
}
auto BBR = domain->AABB(x_AABB,y_AABB);
#pragma omp parallel for
for (size_t i = 0; i < domain->size_local_faces(); i++)
{
auto face = domain->face(i);
double E = (*domain->face(i))["solar_el"_s];
if (E < 5)
{
(*face)["z_prime"_s]= 0; //unshadowed
(*face)["shadow"_s]= 0;
continue;
}
for (size_t j = 0; j < BBR->n_rows; j++)
{
for (size_t k = 0; k < BBR->n_cols; k++)
{
if (BBR->pt_in_rect(face->vertex(0), BBR->get_rect(j, k)) || //pt1
BBR->pt_in_rect(face->vertex(1), BBR->get_rect(j, k)) || //pt2
BBR->pt_in_rect(face->vertex(2), BBR->get_rect(j, k))) //pt3
{
//#pragma omp critical
// {
BBR->get_rect(j, k)->triangles.push_back(face);
// }
}
}
}
//init memory
auto& tv = face->make_module_data<module_shadow_face_info>(ID);
// module_shadow_face_info* tv = new module_shadow_face_info;
//face->set_module_data(ID, tv);
tv.z_prime = CGAL::centroid(face->vertex(0)->point(), face->vertex(1)->point(), face->vertex(2)->point()).z();
}
// LOG_DEBUG << "AABB is " <<BBR->n_rows << "x" << BBR->n_rows;
// for (size_t j = 0; j < BBR->n_rows; j++)
// {
// for (size_t k = 0; k < BBR->n_cols; k++)
// {
// LOG_DEBUG << BBR->get_rect(j, k)->triangles.size();
// }
// }
#pragma omp parallel for
for (size_t i = 0; i < BBR->n_rows; i++)
{
for (size_t ii = 0; ii < BBR->n_cols; ii++)
{
//sort descending
tbb::parallel_sort(BBR->get_rect(i, ii)->triangles.begin(), BBR->get_rect(i, ii)->triangles.end(),
[](triangulation::Face_handle fa, triangulation::Face_handle fb)->bool
{
auto& fa_info = fa->get_module_data<module_shadow_face_info>(
"Marsh_shading_iswr");
auto& fb_info = fb->get_module_data<module_shadow_face_info>(
"Marsh_shading_iswr");
return fa_info.z_prime > fb_info.z_prime;
});
size_t num_tri = BBR->get_rect(i, ii)->triangles.size();
for (size_t j = 0; j < num_tri; j++)
{
triangulation::Face_handle face_j = BBR->get_rect(i, ii)->triangles.at(j);
K::Triangle_2 tj(K::Point_2(face_j->vertex(0)->point().x(), face_j->vertex(0)->point().y()),
K::Point_2(face_j->vertex(1)->point().x(), face_j->vertex(1)->point().y()),
K::Point_2(face_j->vertex(2)->point().x(), face_j->vertex(2)->point().y()));
CGAL::Bbox_2 bj(tj.bbox());
//compare to other triangles
for (size_t k = j + 1; k < num_tri; k++)
{
triangulation::Face_handle face_k = BBR->get_rect(i, ii)->triangles.at(k);
auto& face_k_info = face_k->get_module_data<module_shadow_face_info>(ID);
if (face_k_info.shadow == 0)
{
//not needed as our sort will ensure face_j > face_k
if(face_j->get_z() > face_k->get_z()) //tj is above tk, and tk is shadded by tj?)
{
K::Triangle_2 tk(K::Point_2(face_k->vertex(0)->point().x(), face_k->vertex(0)->point().y()),
K::Point_2(face_k->vertex(1)->point().x(), face_k->vertex(1)->point().y()),
K::Point_2(face_k->vertex(2)->point().x(), face_k->vertex(2)->point().y()));
CGAL::Bbox_2 bk(tk.bbox());
if (CGAL::do_overlap(bk, bj)) {
bool collision = face_k->intersects(face_j);
if (collision) {
face_k_info.shadow = 1;
}
}
}
}
}
auto& face_info = face_j->get_module_data<module_shadow_face_info>(ID);
(*face_j)["shadow"_s] = face_info.shadow;
(*face_j)["z_prime"_s]= face_info.z_prime;
}
}
}
// here we need to 'undo' the rotation we applied.
#pragma omp parallel for
for (size_t i = 0; i < domain->size_local_vertex(); i++)
{
auto vert = domain->vertex(i);
auto vf = vert->get_module_data<vertex_data>(ID);
vert->set_point(vf->org_vertex);
}
}
Marsh_shading_iswr::~Marsh_shading_iswr()
{
}