Library of Assembled Shared Sources
mesh_interpolator.h
Go to the documentation of this file.
1/** @file
2 * @author Bram de Greve (bram@cocamware.com)
3 * @author Tom De Muer (tom@cocamware.com)
4 *
5 * *** BEGIN LICENSE INFORMATION ***
6 *
7 * The contents of this file are subject to the Common Public Attribution License
8 * Version 1.0 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://lass.sourceforge.net/cpal-license. The License is based on the
11 * Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover
12 * use of software over a computer network and provide for limited attribution for
13 * the Original Developer. In addition, Exhibit A has been modified to be consistent
14 * with Exhibit B.
15 *
16 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
17 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
18 * language governing rights and limitations under the License.
19 *
20 * The Original Code is LASS - Library of Assembled Shared Sources.
21 *
22 * The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
23 * The Original Developer is the Initial Developer.
24 *
25 * All portions of the code written by the Initial Developer are:
26 * Copyright (C) 2004-2011 the Initial Developer.
27 * All Rights Reserved.
28 *
29 * Contributor(s):
30 *
31 * Alternatively, the contents of this file may be used under the terms of the
32 * GNU General Public License Version 2 or later (the GPL), in which case the
33 * provisions of GPL are applicable instead of those above. If you wish to allow use
34 * of your version of this file only under the terms of the GPL and not to allow
35 * others to use your version of this file under the CPAL, indicate your decision by
36 * deleting the provisions above and replace them with the notice and other
37 * provisions required by the GPL License. If you do not delete the provisions above,
38 * a recipient may use your version of this file under either the CPAL or the GPL.
39 *
40 * *** END LICENSE INFORMATION ***
41 */
42
43
44
45/** @class lass::spat::MeshInterpolator
46 * Interface for interpolators on meshes.
47 * @brief a planar mesh
48 * @author Tom De Muer [TDM]
49 * @relates PlanarMesh
50 */
51
52#ifndef LASS_GUARDIAN_OF_INCLUSION_SPAT_MESH_INTERPOLATOR_H
53#define LASS_GUARDIAN_OF_INCLUSION_SPAT_MESH_INTERPOLATOR_H
54
55#include "spat_common.h"
56#include "planar_mesh.h"
57#include "../meta/null_type.h"
58
59namespace lass
60{
61namespace spat
62{
63
64
65template<typename T>
66void barycenters( const prim::Point2D<T>& q, const prim::Point2D<T>& a, const prim::Point2D<T>& b, const prim::Point2D<T>& c,
67 T& bA, T& bB, T& bC )
68{
69 typedef prim::Vector2D<T> TVector2D;
70
71 TVector2D v02 = a-c;
72 TVector2D v12 = b-c;
73 TVector2D vq2 = q-c;
74
75 T m00 = dot(v02,v02);
76 T m01 = dot(v02,v12);
77 T m11 = dot(v12,v12);
78 T r0 = dot(v02,vq2);
79 T r1 = dot(v12,vq2);
80 T det = m00*m11-m01*m01;
81
82 LASS_ASSERT( det != 0 );
83
84 T invDet = static_cast<T>(1)/det;
85
86 bA = (m11*r0-m01*r1)*invDet;
87 bB = (m00*r1-m01*r0)*invDet;
88 bC = static_cast<T>(1) - bA - bB;
89}
90
91
92template<typename T, typename TPI>
93class MeshInterpolator
94{
95public:
96 typedef prim::Aabb2D<T> TAabb2D;
97public:
99 typedef typename TPlanarMesh::TPoint2D TPoint2D;
100 typedef std::vector<TPoint2D> TPolyLine2D;
101
102 MeshInterpolator( const TAabb2D& iAabb );
103 virtual ~MeshInterpolator() {}
104
105 const TPlanarMesh& mesh() const { return mesh_; }
106 const TAabb2D& aabb() const { return aabb_; }
107
108 virtual void insertSite( const TPoint2D& iPoint, const TPI& iPointInfo );
109 virtual void insertPolyLine( const TPolyLine2D& iPoly, const TPI& iPointInfo );
110 virtual TPI interpolate( const TPoint2D& iQuery ) const = 0;
111 template <typename OutputIterator> OutputIterator interpolate( const TPolyLine2D& iQuery, OutputIterator oOutput ) const;
112protected:
113 MeshInterpolator() {}
114
115 typedef std::deque<TPI> TInfoList; /**< type must support stable iterators */
116 TInfoList& info() { return info_; }
117
118private:
119 TPlanarMesh mesh_;
120 TAabb2D aabb_;
121
122 TInfoList info_;
123};
124
125
126template<typename T, typename TPI>
127MeshInterpolator<T,TPI>::MeshInterpolator( const TAabb2D& iAabb ) : mesh_( iAabb )
128{
129 aabb_ = iAabb;
130}
131
132template<typename T, typename TPI>
133void MeshInterpolator<T,TPI>::insertSite( const TPoint2D& iPoint, const TPI& iPointInfo )
134{
135 if (!aabb_.contains( iPoint ))
136 {
137 LASS_THROW("MeshInterpolator: cannot insert point outside bounding box");
138 }
139
140 typename TPlanarMesh::TEdge* e = mesh_.insertSite( iPoint );
141 //e = mesh_.locate( iPoint );
142 //LASS_ASSERT( TPlanarMesh::org(e) == iPoint );
143
144 info_.push_back( iPointInfo );
145 TPlanarMesh::setPointHandle( e, &info_.back() );
146}
147
148template<typename T, typename TPI>
149void MeshInterpolator<T,TPI>::insertPolyLine( const TPolyLine2D& iPoly, const TPI& iPointInfo )
150{
151 if (iPoly.size() < 2)
152 {
153 LASS_THROW("MeshInterpolator: A poly line needs at least two vertices ... poly, remember?");
154 }
155
156 for (size_t i = 0; i < iPoly.size(); ++i)
157 {
158 if (!aabb_.contains( iPoly[i] ))
159 {
160 LASS_THROW("MeshInterpolator: cannot insert point outside bounding box");
161 }
162 }
163
164 info_.push_back( iPointInfo );
165 for (size_t i = 1; i < iPoly.size(); ++i)
166 {
167 mesh_.insertEdge(typename TPlanarMesh::TLineSegment2D(iPoly[i - 1], iPoly[i]), meta::EmptyType(),meta::EmptyType(),&info_.back(), true);
168 }
169
170 /*
171 for (size_t i = 0; i < iPoly.size(); ++i)
172 {
173 typename TPlanarMesh::TEdge* e = mesh_.locate(iPoly[i]);
174 LASS_ASSERT(TPlanarMesh::org(e) == iPoly[i]);
175 TPlanarMesh::setPointHandle(e, &info_.back());
176 }
177 */
178}
179
180
181/** @class lass::spat::LinearMeshInterpolator
182 * Interpolator working on triangulated mesh. Interpolation is done linearly by finding a
183 * triangle containing the point of interest. Via barycentric coordinates the linear weighted
184 * interpolation is performed and returned.
185 * Buildup of mesh is incremental so after querying for interpolation new points can be inserted.
186 * @brief a linear interpolator using planar meshes
187 * @author Tom De Muer [TDM]
188 * @relates PlanarMesh
189 */
190
191
192template<typename T, typename TPI>
193class LinearMeshInterpolator : public MeshInterpolator<T,TPI>
194{
195public:
196 typedef typename MeshInterpolator<T,TPI>::TPoint2D TPoint2D;
197 typedef typename MeshInterpolator<T,TPI>::TAabb2D TAabb2D;
198 typedef typename MeshInterpolator<T,TPI>::TPolyLine2D TPolyLine2D;
199 typedef typename MeshInterpolator<T,TPI>::TPlanarMesh TPlanarMesh;
200
201 LinearMeshInterpolator( const TAabb2D& iAabb, const TPI& iValueOutside );
202 virtual ~LinearMeshInterpolator() {}
203 TPI interpolate( const TPoint2D& iQuery ) const override;
204 template <typename OutputIterator> OutputIterator interpolate( const TPolyLine2D& iQuery, OutputIterator oOutput ) const;
205
206private:
207 LinearMeshInterpolator() {}
208 virtual TPI interpolate( const TPoint2D& iQuery, typename TPlanarMesh::TEdge* iEdge ) const;
209 TPI valueOutside_;
210};
211
212
213template<typename T, typename TPI>
214LinearMeshInterpolator<T,TPI>::LinearMeshInterpolator( const TAabb2D& iAabb, const TPI& iValueOutside ) : MeshInterpolator<T,TPI>( iAabb )
215{
216 valueOutside_ = iValueOutside;
217 TPoint2D topleft( iAabb.min().x, iAabb.max().y );
218 TPoint2D topright( iAabb.max().x, iAabb.max().y );
219 TPoint2D bottomleft( iAabb.min().x, iAabb.min().y );
220 TPoint2D bottomright( iAabb.max().x, iAabb.min().y );
221
222 typename TPlanarMesh::TEdge* e;
223
224 this->info().push_back(iValueOutside);
225
226 e = this->mesh().locate(topleft);
227 LASS_ASSERT(TPlanarMesh::org(e) == topleft);
228 TPlanarMesh::setPointHandle(e, &this->info().back());
229
230 e = this->mesh().locate(topright);
231 LASS_ASSERT(TPlanarMesh::org(e) == topright);
232 TPlanarMesh::setPointHandle( e, &this->info().back() );
233
234 e = this->mesh().locate(bottomleft);
235 LASS_ASSERT(TPlanarMesh::org(e) == bottomleft);
236 TPlanarMesh::setPointHandle(e, &this->info().back());
237
238 e = this->mesh().locate(bottomright);
239 LASS_ASSERT(TPlanarMesh::org(e) == bottomright);
240 TPlanarMesh::setPointHandle( e, &this->info().back() );
241
242}
243
244template<typename T, typename TPI>
245TPI LinearMeshInterpolator<T,TPI>::interpolate( const TPoint2D& iQuery, typename TPlanarMesh::TEdge* e ) const
246{
247 if (!this->aabb().contains(iQuery))
248 return valueOutside_;
249
250 TPoint2D a = TPlanarMesh::fastOrg(e);
251 TPoint2D b = TPlanarMesh::fastDest(e);
252 TPoint2D c = TPlanarMesh::fastDest(e->lNext());
253
254 TPI* ia = TPlanarMesh::pointHandle(e);
255 TPI* ib = TPlanarMesh::pointHandle(e->lNext());
256 TPI* ic = TPlanarMesh::pointHandle(e->lNext()->lNext());
257
258 T ba,bb,bc;
259
260 barycenters(iQuery, a, b, c, ba, bb, bc);
261
262 return (*ia)*ba+(*ib)*bb+(*ic)*bc;
263}
264
265
266template<typename T, typename TPI>
267TPI LinearMeshInterpolator<T,TPI>::interpolate( const TPoint2D& iQuery ) const
268{
269 typename TPlanarMesh::TEdge* e = this->mesh().locate(iQuery);
270 if (this->mesh().isBoundingPoint(TPlanarMesh::fastOrg(e)) && !TPlanarMesh::hasLeftFace(e))
271 e = e->sym();
272 return interpolate(iQuery,e);
273}
274
275template<typename T, typename TPI>
276template <typename OutputIterator>
277OutputIterator LinearMeshInterpolator<T,TPI>::interpolate( const TPolyLine2D& iQuery, OutputIterator oOutput ) const
278{
279 /* This function can be optimized. What is done now is compute all intersection points from a poly line with
280 the mesh. Subsequent for all these points the interpolated value is determined. Each of these subsequent interpolations
281 requires a locate (has now been partially optimized away) although it must be clear that that information has already been retrieved by the walkIntersections. The
282 points of intersection always lie on an edge (of course, or it wouldn't be intersections with edges) and computing the bary-
283 centric coordinates is overkill. So an optimization consists of:
284 * keeping track of the edges passed together with the intersection point
285 * compute the values on the org and dest of crossed edges and use this for interpolation
286 */
287
288 LASS_ENFORCE(iQuery.size()>1);
289 typedef std::pair<TPoint2D, typename TPlanarMesh::TEdge*> TPointEdgePair;
290 std::vector<TPointEdgePair> crossings;
291 //TPolyLine2D crossings;
292 for (size_t i=0;i<iQuery.size()-1;++i)
293 {
294 crossings.push_back(TPointEdgePair(iQuery[i],this->mesh().locate(iQuery[i])));
295 this->mesh().walkIntersections(typename TPlanarMesh::TLineSegment2D(iQuery[i],iQuery[i+1]),
296 std::back_inserter(crossings));
297 }
298 crossings.push_back(TPointEdgePair(iQuery.back(),this->mesh().locate(iQuery.back())));
299
300 TPoint2D lastInterpolate = crossings[0].first;
301 typename TPlanarMesh::TEdge* interpEdge = crossings[0].second;
302 if (this->mesh().isBoundingPoint(TPlanarMesh::fastOrg(interpEdge)) && !TPlanarMesh::hasLeftFace(interpEdge))
303 interpEdge = interpEdge->sym();
304 (*oOutput++) = std::pair<TPoint2D, TPI>(crossings[0].first,interpolate(crossings[0].first,interpEdge));
305 for (size_t i=1;i<crossings.size();++i)
306 {
307 if (crossings[i].first!=lastInterpolate)
308 {
309 interpEdge = crossings[i].second;
310 if (this->mesh().isBoundingPoint(TPlanarMesh::fastOrg(interpEdge)) && !TPlanarMesh::hasLeftFace(interpEdge))
311 interpEdge = interpEdge->sym();
312 (*oOutput++) = std::pair<TPoint2D, TPI>(crossings[i].first,interpolate(crossings[i].first,crossings[i].second ));
313 lastInterpolate = crossings[i].first;
314 }
315 }
316 return oOutput;
317}
318
319
320}
321}
322#endif
your momma's axis aligned bounding box.
Definition aabb_2d.h:89
std::deque< TPI > TInfoList
type must support stable iterators
TEdge * locate(const TPoint2D &iPoint, TEdge *iHint=0) const
locate an edge of the triangle containing iPoint
spatial subdivisions, quadtrees, octrees, meshes in 2D and 3D, triangulators, ...
Definition aabb8_tree.h:80
Library for Assembled Shared Sources.
Definition config.h:53