QGIS API Documentation  3.26.3-Buenos Aires (65e4edfdad)
qgsraycastingutils_p.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgsraycastingutils_h.cpp
3  --------------------------------------
4  Date : June 2018
5  Copyright : (C) 2018 by Martin Dobias
6  Email : wonder dot sk at gmail dot com
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgsraycastingutils_p.h"
17 
18 #include "qgis.h"
19 #include "qgsaabb.h"
20 
21 #include <Qt3DRender/QCamera>
22 
24 
25 
26 namespace QgsRayCastingUtils
27 {
28 
29 // copied from qt3d/src/render/raycasting/qray3d_p.h + qray3d.cpp
30 // by KDAB, licensed under the terms of LGPL
31 
32 
33  Ray3D::Ray3D()
34  : m_direction( 0.0f, 0.0f, 1.0f )
35  {
36  }
37 
38  Ray3D::Ray3D( QVector3D origin, QVector3D direction, float distance )
39  : m_origin( origin )
40  , m_direction( direction )
41  , m_distance( distance )
42  {}
43 
44  QVector3D Ray3D::origin() const
45  {
46  return m_origin;
47  }
48 
49  void Ray3D::setOrigin( QVector3D value )
50  {
51  m_origin = value;
52  }
53 
54  QVector3D Ray3D::direction() const
55  {
56  return m_direction;
57  }
58 
59  void Ray3D::setDirection( QVector3D value )
60  {
61  if ( value.isNull() )
62  return;
63 
64  m_direction = value;
65  }
66 
67  float Ray3D::distance() const
68  {
69  return m_distance;
70  }
71 
72  void Ray3D::setDistance( float distance )
73  {
74  m_distance = distance;
75  }
76 
77  QVector3D Ray3D::point( float t ) const
78  {
79  return m_origin + t * m_direction;
80  }
81 
82  Ray3D &Ray3D::transform( const QMatrix4x4 &matrix )
83  {
84  m_origin = matrix * m_origin;
85  m_direction = matrix.mapVector( m_direction );
86 
87  return *this;
88  }
89 
90  Ray3D Ray3D::transformed( const QMatrix4x4 &matrix ) const
91  {
92  return Ray3D( matrix * m_origin, matrix.mapVector( m_direction ) );
93  }
94 
95  bool Ray3D::operator==( const Ray3D &other ) const
96  {
97  return m_origin == other.origin() && m_direction == other.direction();
98  }
99 
100  bool Ray3D::operator!=( const Ray3D &other ) const
101  {
102  return !( *this == other );
103  }
104 
105  bool Ray3D::contains( QVector3D point ) const
106  {
107  const QVector3D ppVec( point - m_origin );
108  if ( ppVec.isNull() ) // point coincides with origin
109  return true;
110  const float dot = QVector3D::dotProduct( ppVec, m_direction );
111  if ( qFuzzyIsNull( dot ) )
112  return false;
113  return qFuzzyCompare( dot * dot, ppVec.lengthSquared() * m_direction.lengthSquared() );
114  }
115 
116  bool Ray3D::contains( const Ray3D &ray ) const
117  {
118  const float dot = QVector3D::dotProduct( m_direction, ray.direction() );
119  if ( !qFuzzyCompare( dot * dot, m_direction.lengthSquared() * ray.direction().lengthSquared() ) )
120  return false;
121  return contains( ray.origin() );
122  }
123 
124  float Ray3D::projectedDistance( QVector3D point ) const
125  {
126  Q_ASSERT( !m_direction.isNull() );
127 
128  return QVector3D::dotProduct( point - m_origin, m_direction ) /
129  m_direction.lengthSquared();
130  }
131 
132  QVector3D Ray3D::project( QVector3D vector ) const
133  {
134  const QVector3D norm = m_direction.normalized();
135  return QVector3D::dotProduct( vector, norm ) * norm;
136  }
137 
138 
139  float Ray3D::distance( QVector3D point ) const
140  {
141  const float t = projectedDistance( point );
142  return ( point - ( m_origin + t * m_direction ) ).length();
143  }
144 
145  QDebug operator<<( QDebug dbg, const Ray3D &ray )
146  {
147  const QDebugStateSaver saver( dbg );
148  dbg.nospace() << "QRay3D(origin("
149  << ray.origin().x() << ", " << ray.origin().y() << ", "
150  << ray.origin().z() << ") - direction("
151  << ray.direction().x() << ", " << ray.direction().y() << ", "
152  << ray.direction().z() << "))";
153  return dbg;
154  }
155 
156 }
157 
158 
160 
161 
162 struct box
163 {
164  box( const QgsAABB &b )
165  {
166  min[0] = b.xMin; min[1] = b.yMin; min[2] = b.zMin;
167  max[0] = b.xMax; max[1] = b.yMax; max[2] = b.zMax;
168  }
169  double min[3];
170  double max[3];
171 };
172 
173 struct ray
174 {
175  ray( double xO, double yO, double zO, double xD, double yD, double zD )
176  {
177  origin[0] = xO; origin[1] = yO; origin[2] = zO;
178  dir[0] = xD; dir[1] = yD; dir[2] = zD;
179  dir_inv[0] = 1 / dir[0]; dir_inv[1] = 1 / dir[1]; dir_inv[2] = 1 / dir[2];
180  }
181  ray( const QgsRayCastingUtils::Ray3D &r )
182  {
183  // ignoring length...
184  origin[0] = r.origin().x(); origin[1] = r.origin().y(); origin[2] = r.origin().z();
185  dir[0] = r.direction().x(); dir[1] = r.direction().y(); dir[2] = r.direction().z();
186  dir_inv[0] = 1 / dir[0]; dir_inv[1] = 1 / dir[1]; dir_inv[2] = 1 / dir[2];
187  }
188  double origin[3];
189  double dir[3];
190  double dir_inv[3];
191 };
192 
193 // https://tavianator.com/fast-branchless-raybounding-box-intersections/
194 // https://tavianator.com/fast-branchless-raybounding-box-intersections-part-2-nans/
195 
196 bool intersection( const box &b, const ray &r )
197 {
198  double t1 = ( b.min[0] - r.origin[0] ) * r.dir_inv[0];
199  double t2 = ( b.max[0] - r.origin[0] ) * r.dir_inv[0];
200 
201  double tmin = std::min( t1, t2 );
202  double tmax = std::max( t1, t2 );
203 
204  for ( int i = 1; i < 3; ++i )
205  {
206  t1 = ( b.min[i] - r.origin[i] ) * r.dir_inv[i];
207  t2 = ( b.max[i] - r.origin[i] ) * r.dir_inv[i];
208 
209  tmin = std::max( tmin, std::min( std::min( t1, t2 ), tmax ) );
210  tmax = std::min( tmax, std::max( std::max( t1, t2 ), tmin ) );
211  }
212 
213  return tmax > std::max( tmin, 0.0 );
214 }
215 
216 
217 namespace QgsRayCastingUtils
218 {
219 
220  bool rayBoxIntersection( const Ray3D &r, const QgsAABB &aabb )
221  {
222  box b( aabb );
223 
224  // intersection() does not like yMin==yMax (excludes borders)
225  if ( b.min[0] == b.max[0] ) b.max[0] += 0.1;
226  if ( b.min[1] == b.max[1] ) b.max[1] += 0.1;
227  if ( b.min[2] == b.max[2] ) b.max[2] += 0.1;
228 
229  return intersection( b, ray( r ) );
230  }
231 
232 // copied from intersectsSegmentTriangle() from qt3d/src/render/backend/triangleboundingvolume.cpp
233 // by KDAB, licensed under the terms of LGPL
234  bool rayTriangleIntersection( const Ray3D &ray,
235  QVector3D a,
236  QVector3D b,
237  QVector3D c,
238  QVector3D &uvw,
239  float &t )
240  {
241  // Note: a, b, c in clockwise order
242  // RealTime Collision Detection page 192
243 
244  const QVector3D ab = b - a;
245  const QVector3D ac = c - a;
246  const QVector3D qp = ( ray.origin() - ray.point( ray.distance() ) );
247 
248  const QVector3D n = QVector3D::crossProduct( ab, ac );
249  const float d = QVector3D::dotProduct( qp, n );
250 
251  if ( d <= 0.0f )
252  return false;
253 
254  const QVector3D ap = ray.origin() - a;
255  t = QVector3D::dotProduct( ap, n );
256 
257  if ( t < 0.0f || t > d )
258  return false;
259 
260  const QVector3D e = QVector3D::crossProduct( qp, ap );
261  uvw.setY( QVector3D::dotProduct( ac, e ) );
262 
263  if ( uvw.y() < 0.0f || uvw.y() > d )
264  return false;
265 
266  uvw.setZ( -QVector3D::dotProduct( ab, e ) );
267 
268  if ( uvw.z() < 0.0f || uvw.y() + uvw.z() > d )
269  return false;
270 
271  const float ood = 1.0f / d;
272  t *= ood;
273  uvw.setY( uvw.y() * ood );
274  uvw.setZ( uvw.z() * ood );
275  uvw.setX( 1.0f - uvw.y() - uvw.z() );
276 
277  return true;
278  }
279 
280 }
281 
282 
operator==
bool operator==(const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)
Definition: qgsfeatureiterator.h:425
qgsaabb.h
qgis.h
QgsAABB::zMax
float zMax
Definition: qgsaabb.h:86
QgsAABB::yMin
float yMin
Definition: qgsaabb.h:82
operator!=
bool operator!=(const QgsFeatureIterator &fi1, const QgsFeatureIterator &fi2)
Definition: qgsfeatureiterator.h:430
QgsAABB::xMin
float xMin
Definition: qgsaabb.h:81
QgsAABB
Axis-aligned bounding box - in world coords.
Definition: qgsaabb.h:33
operator<<
QDataStream & operator<<(QDataStream &out, const QgsFeature &feature)
Writes the feature to stream out. QGIS version compatibility is not guaranteed.
Definition: qgsfeature.cpp:405
c
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c
Definition: porting_processing.dox:1
QgsAABB::yMax
float yMax
Definition: qgsaabb.h:85
QgsAABB::zMin
float zMin
Definition: qgsaabb.h:83
QgsAABB::xMax
float xMax
Definition: qgsaabb.h:84
qgsraycastingutils_p.h