Developer Documentation
GeometryKernel.hh
1#pragma once
2/*===========================================================================*\
3 * *
4 * OpenVolumeMesh *
5 * Copyright (C) 2011 by Computer Graphics Group, RWTH Aachen *
6 * www.openvolumemesh.org *
7 * *
8 *---------------------------------------------------------------------------*
9 * This file is part of OpenVolumeMesh. *
10 * *
11 * OpenVolumeMesh is free software: you can redistribute it and/or modify *
12 * it under the terms of the GNU Lesser General Public License as *
13 * published by the Free Software Foundation, either version 3 of *
14 * the License, or (at your option) any later version with the *
15 * following exceptions: *
16 * *
17 * If other files instantiate templates or use macros *
18 * or inline functions from this file, or you compile this file and *
19 * link it with other files to produce an executable, this file does *
20 * not by itself cause the resulting executable to be covered by the *
21 * GNU Lesser General Public License. This exception does not however *
22 * invalidate any other reasons why the executable file might be *
23 * covered by the GNU Lesser General Public License. *
24 * *
25 * OpenVolumeMesh is distributed in the hope that it will be useful, *
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
28 * GNU Lesser General Public License for more details. *
29 * *
30 * You should have received a copy of the GNU LesserGeneral Public *
31 * License along with OpenVolumeMesh. If not, *
32 * see <http://www.gnu.org/licenses/>. *
33 * *
34\*===========================================================================*/
35
36#include <cassert>
37#include <iostream>
38#include <type_traits>
39
40#include <OpenVolumeMesh/Geometry/VectorT.hh>
41#include <OpenVolumeMesh/Core/TopologyKernel.hh>
42
43namespace OpenVolumeMesh {
44
45// TODO: rename this and put in detail namespace:
46template <class VecT>
47using GeometryKernelT = PropertyPtr<VecT, Entity::Vertex>;
48
49template <class VecT, class TopologyKernelT = TopologyKernel>
50class GeometryKernel : public TopologyKernelT {
51public:
52
53 using PointT = VecT; // OVM legacy
54 using Point = VecT; // OpenMesh compatiblity
55 using KernelT = TopologyKernelT;
56
57 template<typename OtherVec, typename OtherTopo>
58 friend class GeometryKernel;
59
61 : TopologyKernelT()
62 , position_{make_prop()}
63 {}
64
65 GeometryKernel(GeometryKernel const& other)
66 : TopologyKernelT(other)
67 , position_{make_prop()}
68 {
69 std::copy(other.position_.begin(), other.position_.end(),
70 position_.begin());
71 }
72
73 GeometryKernel operator=(GeometryKernel const& other)
74 {
75 if (this == &other)
76 return *this;
77 // I wish this was not necessary, but with only the templated
78 // assignment operator, clang gives us a compile error that
79 // the assignment operator is implicitly deleted.
80 // Also, this helps only comparing identity if we actually have
81 // the same type as `other`.
82 return this->template operator=<TopologyKernelT>(other);
83 }
84
90 template<typename OtherTopoKernelT>
93 {
94 TopologyKernel::operator=(static_cast<TopologyKernel const&>(other));
95
96 // re-create position property:
97 position_ = make_prop();
98
99 // TODO: assignment with different (convertible) vector types would be neat.
100 std::copy(other.position_.begin(), other.position_.end(),
101 position_.begin());
102 return *this;
103 }
104
105 GeometryKernel& operator=(GeometryKernel &&other) = delete;
106 GeometryKernel(GeometryKernel&& other) = default;
107
108 using TopologyKernelT::add_vertex;
109
111 VertexHandle add_vertex(const VecT& _p) {
112 VH vh = TopologyKernelT::add_vertex();
113 position_[vh] = _p;
114 return vh;
115 }
116
118 //[[deprecated("Use VecT& vertex(VH) instead.")]]
119 void set_vertex(VertexHandle _vh, const VecT& _p) {
120
121 assert(_vh.idx() < (int)position_.size());
122
123 position_[_vh] = _p;
124 }
125
127 const VecT& vertex(VertexHandle _vh) const {
128 return position_[_vh];
129 }
130
131 void swap_vertices(std::vector<VecT> &_other) {
132 position_.swap(_other);
133 }
134
135public:
136
137 typename PointT::value_type length(HalfEdgeHandle _heh) const {
138 return vector(_heh).length();
139 }
140
141 typename PointT::value_type length(EdgeHandle _eh) const {
142 return vector(_eh).length();
143 }
144
145 PointT vector(HalfEdgeHandle _heh) const {
146
147 const typename TopologyKernelT::Edge& e = TopologyKernelT::halfedge(_heh);
148 return (vertex(e.to_vertex()) - vertex(e.from_vertex()));
149 }
150
151 PointT vector(EdgeHandle _eh) const {
152
153 const typename TopologyKernelT::Edge& e = TopologyKernelT::edge(_eh);
154 return (vertex(e.to_vertex()) - vertex(e.from_vertex()));
155 }
156
157 PointT barycenter(EdgeHandle _eh) const {
158 return PointT(0.5 * vertex(TopologyKernelT::edge(_eh).from_vertex()) +
159 0.5 * vertex(TopologyKernelT::edge(_eh).to_vertex()));
160 }
161
162 PointT barycenter(FaceHandle _fh) const {
163 PointT p(typename PointT::value_type(0));
164 typename PointT::value_type valence = 0;
165 HalfFaceVertexIter hfv_it =
166 TopologyKernelT::hfv_iter(TopologyKernelT::halfface_handle(_fh, 0));
167 for(; hfv_it.valid(); ++hfv_it, valence += 1) {
168 p += vertex(*hfv_it);
169 }
170 p /= valence;
171 return p;
172 }
173
174 PointT barycenter(CellHandle _ch) const {
175 PointT p(typename PointT::value_type(0));
176 typename PointT::value_type valence = 0;
177 CellVertexIter cv_it = TopologyKernelT::cv_iter(_ch);
178 for(; cv_it.valid(); ++cv_it, valence += 1) {
179 p += vertex(*cv_it);
180 }
181 p /= valence;
182 return p;
183 }
184
187 PointT normal(HalfFaceHandle _hfh) const
188 {
189 if(TopologyKernelT::halfface(_hfh).halfedges().size() < 3) {
190 std::cerr << "Warning: Degenerate face: "
191 << TopologyKernelT::face_handle(_hfh) << std::endl;
192 return PointT {0.0, 0.0, 0.0};
193 }
194
195 const std::vector<HalfEdgeHandle>& halfedges = TopologyKernelT::halfface(_hfh).halfedges();
196 std::vector<HalfEdgeHandle>::const_iterator he_it = halfedges.begin();
197
198 const PointT &p1 = vertex(TopologyKernelT::halfedge(*he_it).from_vertex());
199 const PointT &p2 = vertex(TopologyKernelT::halfedge(*he_it).to_vertex());
200 ++he_it;
201 const PointT &p3 = vertex(TopologyKernelT::halfedge(*he_it).to_vertex());
202
203 const PointT n = (p2 - p1).cross(p3 - p2);
204 return n.normalized();
205 }
206
207 GeometryKernelT<VecT> const& vertex_positions() const & {return position_;}
208 GeometryKernelT<VecT> & vertex_positions() & {return position_;}
209
210private:
211 GeometryKernelT<VecT> get_prop() {
212 auto prop = this->template get_property<VecT, Entity::Vertex>("ovm:position");
213 assert(prop.has_value());
214 return *prop;
215 }
216 GeometryKernelT<VecT> make_prop() {
217 auto prop = this->template create_shared_property<VecT, Entity::Vertex>("ovm:position", VecT(0));
218 assert(prop.has_value());
219 return *prop;
220 }
221
222private:
223 GeometryKernelT<VecT> position_;
224
225};
226
227} // Namespace OpenVolumeMesh
228
VertexHandle add_vertex(const VecT &_p)
Add a geometric point to the mesh.
void set_vertex(VertexHandle _vh, const VecT &_p)
Set the coordinates of point _vh.
const VecT & vertex(VertexHandle _vh) const
Get point _vh's coordinates.
PointT normal(HalfFaceHandle _hfh) const
GeometryKernel operator=(GeometryKernel< VecT, OtherTopoKernelT > const &other)
size_t n() const
Get number of entities of given kind in mesh.
size_t valence(VertexHandle _vh) const
Get valence of vertex (number of incident edges)