21 #include <Qt3DRender/QCamera>
26 namespace QgsRayCastingUtils
34 : m_direction( 0.0f, 0.0f, 1.0f )
38 Ray3D::Ray3D( QVector3D origin, QVector3D direction,
float distance )
40 , m_direction( direction )
41 , m_distance( distance )
44 QVector3D Ray3D::origin()
const
49 void Ray3D::setOrigin( QVector3D value )
54 QVector3D Ray3D::direction()
const
59 void Ray3D::setDirection( QVector3D value )
67 float Ray3D::distance()
const
72 void Ray3D::setDistance(
float distance )
74 m_distance = distance;
77 QVector3D Ray3D::point(
float t )
const
79 return m_origin + t * m_direction;
82 Ray3D &Ray3D::transform(
const QMatrix4x4 &matrix )
84 m_origin = matrix * m_origin;
85 m_direction = matrix.mapVector( m_direction );
90 Ray3D Ray3D::transformed(
const QMatrix4x4 &matrix )
const
92 return Ray3D( matrix * m_origin, matrix.mapVector( m_direction ) );
97 return m_origin == other.origin() && m_direction == other.direction();
102 return !( *
this == other );
105 bool Ray3D::contains( QVector3D point )
const
107 QVector3D ppVec( point - m_origin );
108 if ( ppVec.isNull() )
110 const float dot = QVector3D::dotProduct( ppVec, m_direction );
111 if ( qFuzzyIsNull( dot ) )
113 return qFuzzyCompare( dot * dot, ppVec.lengthSquared() * m_direction.lengthSquared() );
116 bool Ray3D::contains(
const Ray3D &ray )
const
118 const float dot = QVector3D::dotProduct( m_direction, ray.direction() );
119 if ( !qFuzzyCompare( dot * dot, m_direction.lengthSquared() * ray.direction().lengthSquared() ) )
121 return contains( ray.origin() );
124 float Ray3D::projectedDistance( QVector3D point )
const
126 Q_ASSERT( !m_direction.isNull() );
128 return QVector3D::dotProduct( point - m_origin, m_direction ) /
129 m_direction.lengthSquared();
132 QVector3D Ray3D::project( QVector3D vector )
const
134 QVector3D norm = m_direction.normalized();
135 return QVector3D::dotProduct( vector, norm ) * norm;
139 float Ray3D::distance( QVector3D point )
const
141 float t = projectedDistance( point );
142 return ( point - ( m_origin + t * m_direction ) ).length();
145 QDebug
operator<<( QDebug dbg,
const Ray3D &ray )
147 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() <<
"))";
175 ray(
double xO,
double yO,
double zO,
double xD,
double yD,
double zD )
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];
181 ray(
const QgsRayCastingUtils::Ray3D &r )
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];
196 bool intersection(
const box &b,
const ray &r )
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];
201 double tmin = std::min( t1, t2 );
202 double tmax = std::max( t1, t2 );
204 for (
int i = 1; i < 3; ++i )
206 t1 = ( b.min[i] - r.origin[i] ) * r.dir_inv[i];
207 t2 = ( b.max[i] - r.origin[i] ) * r.dir_inv[i];
209 tmin = std::max( tmin, std::min( std::min( t1, t2 ), tmax ) );
210 tmax = std::min( tmax, std::max( std::max( t1, t2 ), tmin ) );
213 return tmax > std::max( tmin, 0.0 );
217 namespace QgsRayCastingUtils
220 bool rayBoxIntersection(
const Ray3D &r,
const QgsAABB &aabb )
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;
229 return intersection( b, ray( r ) );
233 bool rayPlaneIntersection(
const Ray3D &r,
const Plane3D &plane, QVector3D &pt )
235 float denom = QVector3D::dotProduct( plane.normal, r.direction() );
236 if ( std::abs( denom ) > 0.0001f )
238 float t = QVector3D::dotProduct( plane.center - r.origin(), plane.normal ) / denom;
250 bool rayTriangleIntersection(
const Ray3D &ray,
260 const QVector3D ab = b - a;
261 const QVector3D ac =
c - a;
262 const QVector3D qp = ( ray.origin() - ray.point( ray.distance() ) );
264 const QVector3D n = QVector3D::crossProduct( ab, ac );
265 const float d = QVector3D::dotProduct( qp, n );
270 const QVector3D ap = ray.origin() - a;
271 t = QVector3D::dotProduct( ap, n );
273 if ( t < 0.0f || t > d )
276 const QVector3D e = QVector3D::crossProduct( qp, ap );
277 uvw.setY( QVector3D::dotProduct( ac, e ) );
279 if ( uvw.y() < 0.0f || uvw.y() > d )
282 uvw.setZ( -QVector3D::dotProduct( ab, e ) );
284 if ( uvw.z() < 0.0f || uvw.y() + uvw.z() > d )
287 const float ood = 1.0f / d;
289 uvw.setY( uvw.y() * ood );
290 uvw.setZ( uvw.z() * ood );
291 uvw.setX( 1.0f - uvw.y() - uvw.z() );
303 static QRect windowViewport( QSize area,
const QRectF &relativeViewport )
305 if ( area.isValid() )
307 const int areaWidth = area.width();
308 const int areaHeight = area.height();
309 return QRect( relativeViewport.x() * areaWidth,
310 ( 1.0 - relativeViewport.y() - relativeViewport.height() ) * areaHeight,
311 relativeViewport.width() * areaWidth,
312 relativeViewport.height() * areaHeight );
314 return relativeViewport.toRect();
318 static QgsRayCastingUtils::Ray3D intersectionRay( QPointF pos,
const QMatrix4x4 &viewMatrix,
319 const QMatrix4x4 &projectionMatrix, QRect viewport )
326 QVector3D nearPos = QVector3D( pos.x(), pos.y(), 0.0f );
327 nearPos = nearPos.unproject( viewMatrix, projectionMatrix, viewport );
328 QVector3D farPos = QVector3D( pos.x(), pos.y(), 1.0f );
329 farPos = farPos.unproject( viewMatrix, projectionMatrix, viewport );
331 return QgsRayCastingUtils::Ray3D( nearPos,
332 ( farPos - nearPos ).normalized(),
333 ( farPos - nearPos ).length() );
337 namespace QgsRayCastingUtils
340 Ray3D rayForViewportAndCamera( QSize area,
342 const QRectF &relativeViewport,
343 const Qt3DRender::QCamera *camera )
345 QMatrix4x4 viewMatrix = camera->viewMatrix();
346 QMatrix4x4 projectionMatrix = camera->projectionMatrix();
347 const QRect viewport = windowViewport( area, relativeViewport );
350 const QPointF glCorrectPos = QPointF( pos.x(), area.isValid() ? area.height() - pos.y() : pos.y() );
351 const auto ray = intersectionRay( glCorrectPos, viewMatrix, projectionMatrix, viewport );
355 Ray3D rayForCameraCenter(
const Qt3DRender::QCamera *camera )
357 QMatrix4x4 inverse = QMatrix4x4( camera->projectionMatrix() * camera->viewMatrix() ).inverted();
359 QVector4D vNear( 0.0, 0.0, -1.0, 1.0 );
360 QVector4D vFar( 0.0, 0.0, 1.0, 1.0 );
361 QVector4D nearPos4D = inverse * vNear;
362 QVector4D farPos4D = inverse * vFar;
371 QVector3D nearPos( ( nearPos4D / nearPos4D.w() ).toVector3D() );
372 QVector3D farPos( ( farPos4D / farPos4D.w() ).toVector3D() );
374 return QgsRayCastingUtils::Ray3D( nearPos,
375 ( farPos - nearPos ).normalized(),
376 ( farPos - nearPos ).length() );