static inline bool qSameDirection(const QVector3D &a , const QVector3D &b) { bool res = false; if (!a.isNull() && !b.isNull()) { float dot = QVector3D::dotProduct(a, b); res = qFskCompare((qreal)dot, a.length() * b.length()); } return res; }
static bool qCalculateNormal(int i, int j, int k, QGeometryData &p, QVector3D *vec = 0) { QVector3D norm; QVector3D *n = &norm; if (vec) n = vec; bool nullTriangle = false; *n = QVector3D::crossProduct(p.vertexAt(j) - p.vertexAt(i), p.vertexAt(k) - p.vertexAt(j)); if (qFskIsNull(n->x())) n->setX(0.0f); if (qFskIsNull(n->y())) n->setY(0.0f); if (qFskIsNull(n->z())) n->setZ(0.0f); if (n->isNull()) { nullTriangle = true; } else { setNormals(i, j, k, p, *n); } return nullTriangle; }
/*! Returns the distance that this vertex is from a line defined by \a point and the unit vector \a direction. If \a direction is a null vector, then it does not define a line. In that case, the distance from \a point to this vertex is returned. \sa distanceToPlane() */ qreal QVector3D::distanceToLine (const QVector3D& point, const QVector3D& direction) const { if (direction.isNull()) return (*this - point).length(); QVector3D p = point + dotProduct(*this - point, direction) * direction; return (*this - p).length(); }
void QMesh::addTri(const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &an, const QVector3D &bn, const QVector3D &cn) { QVector3D anorm = an.isNull() ? QVector3D::normal(a, b, c) : an; QVector3D bnorm = bn.isNull() ? QVector3D::normal(a, b, c) : bn; QVector3D cnorm = cn.isNull() ? QVector3D::normal(a, b, c) : cn; if (sm == Smooth) { geom->appendSmooth(a, anorm, initv); geom->appendSmooth(b, bnorm, initv); geom->appendSmooth(c, cnorm, initv); } else { geom->appendFaceted(a, anorm); geom->appendFaceted(b, bnorm); geom->appendFaceted(c, cnorm); } count += 3; }
/*! \internal */ void QGraphicsRotation3D::applyTo(QMatrix4x4 *matrix) const { qreal angle = this->angle(); QVector3D axis = this->axis(); QVector3D origin = this->origin(); if (angle == 0. || axis.isNull()) return; matrix->translate(origin); matrix->rotate(angle, axis.x(), axis.y(), axis.z()); matrix->translate(-origin); }
void tst_QGLBuilder::addQuadRandom() { QFETCH(int, size); QFETCH(int, type); int n = qSqrt(size); size = n * n; QVector3DArray data; data.reserve(size); for (int i = 0; i < size; ++i) { // make sure (in face of randomness) we get a planar quad QVector3D origin = randVector(); QVector3D a; while (a.isNull()) a = randVector(); QVector3D b; while (b.isNull()) b = randVector(); data.append(origin, a, a+b, b); } addQuadBenchMarks(data, type); }
void GLGameModel::pointInDirection(QVector3D d) { if(d.isNull()) { setAngleY(0.0); return; } // roate the object to point in direction // we only rotate in the x-z plane float cos_y = d.normalized().z(); setAngleY(360.0 * qAcos(cos_y) / (2*M_PI)); //qDebug() << "pointing to" << d << "with angles" << angleX << angleY << angleZ; }
void Patch::addTri( const QVector3D &a, const QVector3D &b, const QVector3D &c, const QVector3D &n ) { QVector3D norm = n.isNull() ? QVector3D::normal( a, b, c ) : n; if (sm == Smooth) { geom->appendSmooth( a, norm, initv ); geom->appendSmooth( b, norm, initv ); geom->appendSmooth( c, norm, initv ); } else { geom->appendFaceted( a, norm ); geom->appendFaceted( b, norm ); geom->appendFaceted( c, norm ); } count += 3; }
/*! Adds to this section a polygonal face made of triangular sub-faces, defined by \a face. The 0'th vertex is used for the center, while the subsequent vertices form the perimeter of the face, which must at minimum be a triangle. If \a face has less than four vertices this function exits without doing anything. This function provides functionality similar to the OpenGL mode GL_POLYGON, except it divides the face into sub-faces around a \b{central point}. The center and perimeter vertices must lie in the same plane (unlike triangle fan). If they do not normals will be incorrectly calculated. \image triangulated-face.png Here the sub-faces are shown divided by green lines. Note how this function handles some re-entrant (non-convex) polygons, whereas addTriangleFan will not support such polygons. If required, the center point can be calculated using the center() function of QGeometryData: \code QGeometryData face; face.appendVertex(perimeter.center()); // perimeter is a QGeometryData face.appendVertices(perimeter); builder.addTriangulatedFace(face); \endcode N sub-faces are generated where \c{N == face.count() - 2}. Each triangular sub-face consists of the center; followed by the \c{i'th} and \c{((i + 1) % N)'th} vertex. The last face generated then is \c{(center, face[N - 1], face[0]}, the closing face. Note that the closing face is automatically created, unlike addTriangleFan(). If no normals are supplied in the vertices of \a face, normals are calculated as per addTriangle(). One normal is calculated, since a face's vertices lie in the same plane. Degenerate triangles are skipped in the same way as addTriangles(). \sa addTriangleFan(), addTriangles() */ void QGLBuilder::addTriangulatedFace(const QGeometryData &face) { if (face.count() < 4) return; QGeometryData f; f.appendGeometry(face); int cnt = f.count(); bool calcNormal = !f.hasField(QGL::Normal); if (calcNormal) { QVector3DArray nm(cnt); f.appendNormalArray(nm); } bool skip = false; QVector3D norm; int k = 0; for (int i = 1; i < cnt; ++i) { int n = i + 1; if (n == cnt) n = 1; if (calcNormal) { skip = qCalculateNormal(0, i, n, f); if (norm.isNull() && !skip) { norm = f.normalAt(0); for (int i = 0; i < cnt; ++i) f.normal(i) = norm; } } if (!skip) dptr->addTriangle(0, i, n, f, k); } dptr->currentNode->setCount(dptr->currentNode->count() + k); }
void Plane3D::setNormal(const QVector3D &normal) { m_vecNormal = normal.isNull() ? normal : normal.normalized(); }
// Compute the normal at a specific point in the patch. // The s and t values vary between 0 and 1. QVector3D QGLBezierPatch::normal(qreal s, qreal t) const { qreal a[4]; qreal b[4]; qreal tx, ty, tz; qreal sx, sy, sz; // Compute the derivative of the surface in t. a[0] = b0(s); a[1] = b1(s); a[2] = b2(s); a[3] = b3(s); b[0] = db0(t); b[1] = db1(t); b[2] = db2(t); b[3] = db3(t); tx = 0.0f; ty = 0.0f; tz = 0.0f; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { tx += a[i] * points[j * 4 + i].x() * b[j]; ty += a[i] * points[j * 4 + i].y() * b[j]; tz += a[i] * points[j * 4 + i].z() * b[j]; } } // Compute the derivative of the surface in s. a[0] = db0(s); a[1] = db1(s); a[2] = db2(s); a[3] = db3(s); b[0] = b0(t); b[1] = b1(t); b[2] = b2(t); b[3] = b3(t); sx = 0.0f; sy = 0.0f; sz = 0.0f; for (int i = 0; i < 4; ++i) { for (int j = 0; j < 4; ++j) { sx += a[i] * points[j * 4 + i].x() * b[j]; sy += a[i] * points[j * 4 + i].y() * b[j]; sz += a[i] * points[j * 4 + i].z() * b[j]; } } // The normal is the cross-product of the two derivatives, // normalized to a unit vector. QVector3D n = QVector3D::normal(QVector3D(sx, sy, sz), QVector3D(tx, ty, tz)); if (n.isNull()) { // A zero normal may occur if one of the patch edges is zero-length. // We correct for this by substituting an overall patch normal that // we compute from two of the sides that are not zero in length. QVector3D sides[4]; QVector3D vectors[2]; sides[0] = points[3] - points[0]; sides[1] = points[15] - points[3]; sides[2] = points[12] - points[15]; sides[3] = points[0] - points[12]; int i = 0; int j = 0; vectors[0] = QVector3D(1.0f, 0.0f, 0.0f); vectors[1] = QVector3D(0.0f, 1.0f, 0.0f); while (i < 2 && j < 4) { if (sides[j].isNull()) ++j; else vectors[i++] = sides[j++]; } n = QVector3D::normal(vectors[0], vectors[1]); } return n; }