Newer
Older
/**
* \file AddLayerToMesh.cpp
Karsten Rink
committed
* \date 2016-01-18
* \brief Implementation of AddLayerToMesh class.
*
* \copyright
* Copyright (c) 2012-2016, OpenGeoSys Community (http://www.opengeosys.org)
* Distributed under a Modified BSD License.
* See accompanying file LICENSE.txt or
* http://www.opengeosys.org/project/license
*
*/
#include "AddLayerToMesh.h"
#include <map>
#include <memory>
#include <numeric>
#include <vector>
#include "logog/include/logog.hpp"
#include "MeshLib/Mesh.h"
#include "MeshLib/Node.h"
#include "MeshLib/Elements/Elements.h"
#include "MeshLib/MeshSurfaceExtraction.h"
Karsten Rink
committed
#include "MeshLib/MeshEditing/DuplicateMeshComponents.h"
#include "MeshLib/MeshEditing/FlipElements.h"
namespace MeshLib
{
/** Extrudes point, line, triangle or quad elements to its higher dimensional
* versions, i.e. line, quad, prism, hexahedron.
*
* @param subsfc_nodes the nodes the elements are based on
* @param sfc_elem the element of the surface that will be extruded
* @param sfc_to_subsfc_id_map relation between the surface nodes of the surface
* element and the ids of the nodes of the subsurface mesh
* @param subsfc_sfc_id_map mapping of the surface nodes of the current mesh
* to the surface nodes of the extruded mesh
*
* @return extruded element (point -> line, line -> quad, tri -> prism, quad ->
* hexahedron)
*/
Karsten Rink
committed
MeshLib::Element* extrudeElement(std::vector<MeshLib::Node*> const& subsfc_nodes,
MeshLib::Element const& sfc_elem,
MeshLib::PropertyVector<std::size_t> const& sfc_to_subsfc_id_map,
std::map<std::size_t, std::size_t> const& subsfc_sfc_id_map)
if (sfc_elem.getDimension() > 2)
return nullptr;
const unsigned nElemNodes(sfc_elem.getNBaseNodes());
MeshLib::Node** new_nodes = new MeshLib::Node*[2*nElemNodes];
for (unsigned j=0; j<nElemNodes; ++j)
{
std::size_t const subsfc_id(
sfc_to_subsfc_id_map[sfc_elem.getNode(j)->getID()]);
new_nodes[j] = subsfc_nodes[subsfc_id];
std::size_t new_idx = (nElemNodes==2) ? (3-j) : (nElemNodes+j);
new_nodes[new_idx] = subsfc_nodes[subsfc_sfc_id_map.at(subsfc_id)];
}
if (sfc_elem.getGeomType() == MeshLib::MeshElemType::LINE)
return new MeshLib::Quad(new_nodes);
if (sfc_elem.getGeomType() == MeshLib::MeshElemType::TRIANGLE)
return new MeshLib::Prism(new_nodes);
if (sfc_elem.getGeomType() == MeshLib::MeshElemType::QUAD)
return new MeshLib::Hex(new_nodes);
return nullptr;
Karsten Rink
committed
}
return addLayerToMesh(mesh, thickness, name, true);
return addLayerToMesh(mesh, thickness, name, false);
MeshLib::Mesh* addLayerToMesh(MeshLib::Mesh const& mesh, double thickness,
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
INFO("Extracting top surface of mesh \"%s\" ... ", mesh.getName().c_str());
int const flag = (on_top) ? -1 : 1;
const MathLib::Vector3 dir(0, 0, flag);
double const angle(90);
std::unique_ptr<MeshLib::Mesh> sfc_mesh (nullptr);
std::string const prop_name("OriginalSubsurfaceNodeIDs");
if (mesh.getDimension() == 3)
sfc_mesh.reset(MeshLib::MeshSurfaceExtraction::getMeshSurface(
mesh, dir, angle, prop_name));
else {
sfc_mesh = (on_top) ? std::unique_ptr<MeshLib::Mesh>(new MeshLib::Mesh(mesh)) :
std::unique_ptr<MeshLib::Mesh>(MeshLib::createFlippedMesh(mesh));
// add property storing node ids
boost::optional<MeshLib::PropertyVector<std::size_t>&> pv(
sfc_mesh->getProperties().createNewPropertyVector<std::size_t>(
prop_name, MeshLib::MeshItemType::Node, 1));
if (pv) {
pv->resize(sfc_mesh->getNNodes());
std::iota(pv->begin(), pv->end(), 0);
} else {
ERR("Could not create and initialize property.");
return nullptr;
}
}
INFO("done.");
// *** add new surface nodes
std::vector<MeshLib::Node*> subsfc_nodes =
MeshLib::copyNodeVector(mesh.getNodes());
std::vector<MeshLib::Element*> subsfc_elements =
MeshLib::copyElementVector(mesh.getElements(), subsfc_nodes);
std::size_t const n_subsfc_nodes(subsfc_nodes.size());
std::vector<MeshLib::Node*> const& sfc_nodes(sfc_mesh->getNodes());
std::size_t const n_sfc_nodes(sfc_nodes.size());
// fetch subsurface node ids PropertyVector
boost::optional<MeshLib::PropertyVector<std::size_t> const&> opt_node_id_pv(
sfc_mesh->getProperties().getPropertyVector<std::size_t>(prop_name));
if (!opt_node_id_pv) {
ERR(
"Need subsurface node ids, but the property \"%s\" is not "
"available.",
prop_name.c_str());
return nullptr;
}
MeshLib::PropertyVector<std::size_t> const& node_id_pv(*opt_node_id_pv);
// *** copy sfc nodes to subsfc mesh node
std::map<std::size_t, std::size_t> subsfc_sfc_id_map;
for (std::size_t k(0); k<n_sfc_nodes; ++k) {
std::size_t const subsfc_id(node_id_pv[k]);
std::size_t const sfc_id(k+n_subsfc_nodes);
subsfc_sfc_id_map.insert(std::make_pair(subsfc_id, sfc_id));
MeshLib::Node const& node(*sfc_nodes[k]);
subsfc_nodes.push_back(new MeshLib::Node(
node[0], node[1], node[2] - (flag * thickness), sfc_id));
}
// *** insert new layer elements into subsfc_mesh
std::vector<MeshLib::Element*> const& sfc_elements(sfc_mesh->getElements());
std::size_t const n_sfc_elements(sfc_elements.size());
for (std::size_t k(0); k<n_sfc_elements; ++k)
subsfc_elements.push_back(extrudeElement(subsfc_nodes, *sfc_elements[k],
node_id_pv,
subsfc_sfc_id_map));
auto new_mesh = new MeshLib::Mesh(name, subsfc_nodes, subsfc_elements);
boost::optional<MeshLib::PropertyVector<int> const&> opt_materials(
mesh.getProperties().getPropertyVector<int>("MaterialIDs")
);
if (opt_materials) {
boost::optional<PropertyVector<int> &> new_materials(
new_mesh->getProperties().createNewPropertyVector<int>("MaterialIDs",
MeshLib::MeshItemType::Cell, 1));
if (!new_materials) {
ERR("Can not set material properties for new layer");
} else {
new_materials->reserve(subsfc_elements.size());
int new_layer_id (*(std::max_element(opt_materials->cbegin(), opt_materials->cend()))+1);
std::copy(opt_materials->cbegin(), opt_materials->cend(), std::back_inserter(*new_materials));
auto const n_new_props(subsfc_elements.size()-mesh.getNElements());
std::fill_n(std::back_inserter(*new_materials), n_new_props, new_layer_id);
}
} else {
ERR(
"Could not copy the property \"MaterialIDs\" since the original "
"mesh does not contain such a property.");
}
return new_mesh;
}
} // namespace MeshLib