예제 #1
0
파일: prl.cpp 프로젝트: oln0ry/RSP6M2
void PRL::GenerationRadians(void)
{
    radians=new Points[ROUND_DEGREE];
    for(quint16 i=0u;i<ROUND_DEGREE;i++)
    {
        radians[i].degree=i;
        radians[i].angle=GetRadianValue(i);
        radians[i].x=qFastCos(radians[i].angle);
        radians[i].y=qFastSin(radians[i].angle);
    }
}
예제 #2
0
void TunerFrame::adjustFreq( double frq )
{
    const double factor = 13.0 / ( 108 - 87.5 );

    const double x = ( frq - 87.5 ) * factor;
    const double field = qwtSqr( qFastSin( x ) * qFastCos( 4.0 * x ) );

    d_thermoTune->setValue( field );

    if ( d_sliderFrequency->value() != frq )
        d_sliderFrequency->setValue( frq );
    if ( d_wheelFrequency->value() != frq )
        d_wheelFrequency->setValue( frq );

    Q_EMIT fieldChanged( field );
}
예제 #3
0
파일: ampfrm.cpp 프로젝트: Spinetta/qwt
void AmpFrame::timerEvent( QTimerEvent * )
{
    static double phs = 0;

    //
    //  This amplifier generates its own input signal...
    //

    const double sig_bass = ( 1.0 + 0.1 * d_knbBass->value() )
        * qFastSin( 13.0 * phs );
    const double sig_mid_l = qFastSin( 17.0 * phs );
    const double sig_mid_r = qFastCos( 17.5 * phs );
    const double sig_trbl_l = 0.5 * ( 1.0 + 0.1 * d_knbTreble->value() )
        * qFastSin( 35.0 * phs );
    const double sig_trbl_r = 0.5 * ( 1.0 + 0.1 * d_knbTreble->value() )
        * qFastSin( 34.0 * phs );

    double sig_l = 0.05 * d_master * d_knbVolume->value()
        * qwtSqr( sig_bass + sig_mid_l + sig_trbl_l );
    double sig_r = 0.05 * d_master * d_knbVolume->value()
        * qwtSqr( sig_bass + sig_mid_r + sig_trbl_r );

    double balance = 0.1 * d_knbBalance->value();
    if ( balance > 0 )
        sig_l *= ( 1.0 - balance );
    else
        sig_r *= ( 1.0 + balance );

    if ( sig_l > 0.01 )
        sig_l = 20.0 * log10( sig_l );
    else
        sig_l = -40.0;

    if ( sig_r > 0.01 )
        sig_r = 20.0 * log10( sig_r );
    else
        sig_r = - 40.0;

    d_thmLeft->setValue( sig_l );
    d_thmRight->setValue( sig_r );

    phs += M_PI / 100;
    if ( phs > M_PI )
        phs = 0;
}
void QQuickDefaultClipNode::updateGeometry()
{
    QSGGeometry *g = geometry();

    if (qFuzzyIsNull(m_radius)) {
        g->allocate(4);
        QSGGeometry::updateRectGeometry(g, m_rect);

    } else {
        int vertexCount = 0;

        // Radius should never exceeds half of the width or half of the height
        qreal radius = qMin(qMin(m_rect.width() / 2, m_rect.height() / 2), m_radius);
        QRectF rect = m_rect;
        rect.adjust(radius, radius, -radius, -radius);

        int segments = qMin(30, qCeil(radius)); // Number of segments per corner.

        g->allocate((segments + 1) * 2);

        QVector2D *vertices = (QVector2D *)g->vertexData();

        for (int part = 0; part < 2; ++part) {
            for (int i = 0; i <= segments; ++i) {
                //### Should change to calculate sin/cos only once.
                qreal angle = qreal(0.5 * M_PI) * (part + i / qreal(segments));
                qreal s = qFastSin(angle);
                qreal c = qFastCos(angle);
                qreal y = (part ? rect.bottom() : rect.top()) - radius * c; // current inner y-coordinate.
                qreal lx = rect.left() - radius * s; // current inner left x-coordinate.
                qreal rx = rect.right() + radius * s; // current inner right x-coordinate.

                vertices[vertexCount++] = QVector2D(rx, y);
                vertices[vertexCount++] = QVector2D(lx, y);
            }
        }

    }
    markDirty(DirtyGeometry);
    setClipRect(m_rect);
}
static void qwtDrawStyle1Needle( QPainter *painter,
    const QPalette &palette, QPalette::ColorGroup colorGroup,
    double length )
{
    const double r[] = { 0.4, 0.3, 1, 0.8, 1, 0.3, 0.4 };
    const double a[] = { -45, -20, -15, 0, 15, 20, 45 };

    QPainterPath path;
    for ( int i = 0; i < 7; i++ )
    {
        const double angle = a[i] / 180.0 * M_PI;
        const double radius = r[i] * length;

        const double x = radius * qFastCos( angle );
        const double y = radius * qFastSin( angle );

        path.lineTo( x, -y );
    }

    painter->setPen( Qt::NoPen );
    painter->setBrush( palette.brush( colorGroup, QPalette::Light ) );
    painter->drawPath( path );
}
예제 #6
0
/*!
  \brief Draw the marker at the knob's front

  \param painter Painter
  \param rect Bounding rectangle of the knob without scale
  \param angle Angle of the marker in degrees
               ( clockwise, 0 at the 12 o'clock position )
*/
void QwtKnob::drawMarker( QPainter *painter,
    const QRectF &rect, double angle ) const
{
    if ( d_data->markerStyle == NoMarker || !isValid() )
        return;

    const double radians = qwtRadians( angle );
    const double sinA = -qFastSin( radians );
    const double cosA = qFastCos( radians );

    const double xm = rect.center().x();
    const double ym = rect.center().y();
    const double margin = 4.0;

    double radius = 0.5 * ( rect.width() - d_data->borderWidth ) - margin;
    if ( radius < 1.0 )
        radius = 1.0;

    int markerSize = d_data->markerSize;
    if ( markerSize <= 0 )
        markerSize = qRound( 0.4 * radius );

    switch ( d_data->markerStyle )
    {
        case Notch:
        case Nub:
        {
            const double dotWidth =
                qMin( double( markerSize ), radius);

            const double dotCenterDist = radius - 0.5 * dotWidth;
            if ( dotCenterDist > 0.0 )
            {
                const QPointF center( xm - sinA * dotCenterDist,
                    ym - cosA * dotCenterDist );

                QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
                ellipse.moveCenter( center );

                QColor c1 = palette().color( QPalette::Light );
                QColor c2 = palette().color( QPalette::Mid );

                if ( d_data->markerStyle == Notch )
                    qSwap( c1, c2 );

                QLinearGradient gradient(
                    ellipse.topLeft(), ellipse.bottomRight() );
                gradient.setColorAt( 0.0, c1 );
                gradient.setColorAt( 1.0, c2 );

                painter->setPen( Qt::NoPen );
                painter->setBrush( gradient );

                painter->drawEllipse( ellipse );
            }
            break;
        }
        case Dot:
        {
            const double dotWidth =
                qMin( double( markerSize ), radius);

            const double dotCenterDist = radius - 0.5 * dotWidth;
            if ( dotCenterDist > 0.0 )
            {
                const QPointF center( xm - sinA * dotCenterDist,
                    ym - cosA * dotCenterDist );

                QRectF ellipse( 0.0, 0.0, dotWidth, dotWidth );
                ellipse.moveCenter( center );

                painter->setPen( Qt::NoPen );
                painter->setBrush( palette().color( QPalette::ButtonText ) );
                painter->drawEllipse( ellipse );
            }

            break;
        }
        case Tick:
        {
            const double rb = qMax( radius - markerSize, 1.0 );
            const double re = radius;

            const QLineF line( xm - sinA * rb, ym - cosA * rb,
                xm - sinA * re, ym - cosA * re );

            QPen pen( palette().color( QPalette::ButtonText ), 0 );
            pen.setCapStyle( Qt::FlatCap );
            painter->setPen( pen );
            painter->drawLine ( line );

            break;
        }
        case Triangle:
        {
            const double rb = qMax( radius - markerSize, 1.0 );
            const double re = radius;

            painter->translate( rect.center() );
            painter->rotate( angle - 90.0 );

            QPolygonF polygon;
            polygon += QPointF( re, 0.0 );
            polygon += QPointF( rb, 0.5 * ( re - rb ) );
            polygon += QPointF( rb, -0.5 * ( re - rb ) );

            painter->setPen( Qt::NoPen );
            painter->setBrush( palette().color( QPalette::ButtonText ) );
            painter->drawPolygon( polygon );

            painter->resetTransform();

            break;
        }
        default:
            break;
    }
}
예제 #7
0
void QTriangulatingStroker::process(const QVectorPath &path, const QPen &pen, const QRectF &)
{
    const qreal *pts = path.points();
    const QPainterPath::ElementType *types = path.elements();
    int count = path.elementCount();
    if (count < 2)
        return;

    float realWidth = qpen_widthf(pen);
    if (realWidth == 0)
        realWidth = 1;

    m_width = realWidth / 2;

    bool cosmetic = pen.isCosmetic();
    if (cosmetic) {
        m_width = m_width * m_inv_scale;
    }

    m_join_style = qpen_joinStyle(pen);
    m_cap_style = qpen_capStyle(pen);
    m_vertices.reset();
    m_miter_limit = pen.miterLimit() * qpen_widthf(pen);

    // The curvyness is based on the notion that I originally wanted
    // roughly one line segment pr 4 pixels. This may seem little, but
    // because we sample at constantly incrementing B(t) E [0<t<1], we
    // will get longer segments where the curvature is small and smaller
    // segments when the curvature is high.
    //
    // To get a rough idea of the length of each curve, I pretend that
    // the curve is a 90 degree arc, whose radius is
    // qMax(curveBounds.width, curveBounds.height). Based on this
    // logic we can estimate the length of the outline edges based on
    // the radius + a pen width and adjusting for scale factors
    // depending on if the pen is cosmetic or not.
    //
    // The curvyness value of PI/14 was based on,
    // arcLength = 2*PI*r/4 = PI*r/2 and splitting length into somewhere
    // between 3 and 8 where 5 seemed to be give pretty good results
    // hence: Q_PI/14. Lower divisors will give more detail at the
    // direct cost of performance.

    // simplfy pens that are thin in device size (2px wide or less)
    if (realWidth < 2.5 && (cosmetic || m_inv_scale == 1)) {
        if (m_cap_style == Qt::RoundCap)
            m_cap_style = Qt::SquareCap;
        if (m_join_style == Qt::RoundJoin)
            m_join_style = Qt::MiterJoin;
        m_curvyness_add = 0.5;
        m_curvyness_mul = CURVE_FLATNESS / m_inv_scale;
        m_roundness = 1;
    } else if (cosmetic) {
        m_curvyness_add = realWidth / 2;
        m_curvyness_mul = CURVE_FLATNESS;
        m_roundness = qMax<int>(4, realWidth * CURVE_FLATNESS);
    } else {
        m_curvyness_add = m_width;
        m_curvyness_mul = CURVE_FLATNESS / m_inv_scale;
        m_roundness = qMax<int>(4, realWidth * m_curvyness_mul);
    }

    // Over this level of segmentation, there doesn't seem to be any
    // benefit, even for huge penWidth
    if (m_roundness > 24)
        m_roundness = 24;

    m_sin_theta = qFastSin(Q_PI / m_roundness);
    m_cos_theta = qFastCos(Q_PI / m_roundness);

    const qreal *endPts = pts + (count<<1);
    const qreal *startPts = 0;

    Qt::PenCapStyle cap = m_cap_style;

    if (!types) {
        // skip duplicate points
        while((pts + 2) < endPts && pts[0] == pts[2] && pts[1] == pts[3])
            pts += 2;
        if ((pts + 2) == endPts)
            return;

        startPts = pts;

        bool endsAtStart = startPts[0] == *(endPts-2) && startPts[1] == *(endPts-1);

        if (endsAtStart || path.hasImplicitClose())
            m_cap_style = Qt::FlatCap;
        moveTo(pts);
        m_cap_style = cap;
        pts += 2;
        lineTo(pts);
        pts += 2;
        while (pts < endPts) {
            if (m_cx != pts[0] || m_cy != pts[1]) {
                join(pts);
                lineTo(pts);
            }
            pts += 2;
        }

        endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);

    } else {
        bool endsAtStart = false;
        while (pts < endPts) {
            switch (*types) {
            case QPainterPath::MoveToElement: {
                if (pts != path.points())
                    endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);

                startPts = pts;
                int end = (endPts - pts) / 2;
                int i = 2; // Start looking to ahead since we never have two moveto's in a row
                while (i<end && types[i] != QPainterPath::MoveToElement) {
                    ++i;
                }
                endsAtStart = startPts[0] == pts[i*2 - 2] && startPts[1] == pts[i*2 - 1];
                if (endsAtStart || path.hasImplicitClose())
                    m_cap_style = Qt::FlatCap;

                moveTo(pts);
                m_cap_style = cap;
                pts+=2;
                ++types;
                break; }
            case QPainterPath::LineToElement:
                if (*(types - 1) != QPainterPath::MoveToElement)
                    join(pts);
                lineTo(pts);
                pts+=2;
                ++types;
                break;
            case QPainterPath::CurveToElement:
                if (*(types - 1) != QPainterPath::MoveToElement)
                    join(pts);
                cubicTo(pts);
                pts+=6;
                types+=3;
                break;
            default:
                Q_ASSERT(false);
                break;
            }
        }

        endCapOrJoinClosed(startPts, pts-2, path.hasImplicitClose(), endsAtStart);
    }
}
예제 #8
0
QGeometryData MgGeometriesData::sphere(qreal radius,int divisions)
{
	QGeometryData geometry;

	// Determine the number of slices and stacks to generate.
	static int const slicesAndStacks[] = {
			4, 4,
			8, 4,
			8, 8,
			16, 8,
			16, 16,
			32, 16,
			32, 32,
			64, 32,
			64, 64,
			128, 64,
			128, 128
	};
	if (divisions < 1)
		divisions = 1;
	else if (divisions > 10)
		divisions = 10;
	int stacks = slicesAndStacks[divisions * 2 - 1];
	int slices = slicesAndStacks[divisions * 2 - 2];

	// Precompute sin/cos values for the slices and stacks.
	const int maxSlices = 128 + 1;
	const int maxStacks = 128 + 1;
	qreal sliceSin[maxSlices];
	qreal sliceCos[maxSlices];
	qreal stackSin[maxStacks];
	qreal stackCos[maxStacks];
	for (int slice = 0; slice < slices; ++slice)
	{
		qreal angle = 2 * M_PI * slice / slices;
		sliceSin[slice] = qFastSin(angle);
		sliceCos[slice] = qFastCos(angle);
	}
	sliceSin[slices] = sliceSin[0]; // Join first and last slice.
	sliceCos[slices] = sliceCos[0];

	for (int stack = 0; stack <= stacks; ++stack)
	{
		qreal angle = M_PI * stack / stacks;
		stackSin[stack] = qFastSin(angle);
		stackCos[stack] = qFastCos(angle);
	}
	stackSin[0] = 0.0f;             // Come to a point at the poles.
	stackSin[stacks] = 0.0f;

	// Create the stacks.
	for (int stack = 0; stack < stacks; ++stack)
	{
		QGeometryData prim;
		qreal z = radius * stackCos[stack];
		qreal nextz = radius * stackCos[stack + 1];
		qreal s = stackSin[stack];
		qreal nexts = stackSin[stack + 1];
		qreal c = stackCos[stack];
		qreal nextc = stackCos[stack + 1];
		qreal r = radius * s;
		qreal nextr = radius * nexts;
		for (int slice = 0; slice <= slices; ++slice)
		{
			prim.appendVertex
			(QVector3D(nextr * sliceSin[slice],
					nextr * sliceCos[slice], nextz));
			prim.appendNormal
			(QVector3D(sliceSin[slice] * nexts,
					sliceCos[slice] * nexts, nextc));

			prim.appendVertex
			(QVector3D(r * sliceSin[slice],
					r * sliceCos[slice], z));
			prim.appendNormal
			(QVector3D(sliceSin[slice] * s,
					sliceCos[slice] * s, c));
		}
		geometry.appendGeometry(prim);
	}
	return geometry;
}
/*!
  Draw a symbol depending on its style

  \param painter Painter
  \param orientation Orientation
  \param from Start point of the interval in target device coordinates
  \param to End point of the interval in target device coordinates

  \sa setStyle()
*/
void QwtIntervalSymbol::draw( QPainter *painter, Qt::Orientation orientation,
    const QPointF &from, const QPointF &to ) const
{
    const qreal pw = qMax( painter->pen().widthF(), qreal( 1.0 ) );

    QPointF p1 = from;
    QPointF p2 = to;
    if ( QwtPainter::roundingAlignment( painter ) )
    {
        p1 = p1.toPoint();
        p2 = p2.toPoint();
    }

    switch ( d_data->style )
    {
        case QwtIntervalSymbol::Bar:
        {
            QwtPainter::drawLine( painter, p1, p2 );
            if ( d_data->width > pw )
            {
                if ( ( orientation == Qt::Horizontal ) 
                    && ( p1.y() == p2.y() ) )
                {
                    const double sw = d_data->width;

                    const double y = p1.y() - sw / 2;
                    QwtPainter::drawLine( painter,
                        p1.x(), y, p1.x(), y + sw );
                    QwtPainter::drawLine( painter,
                        p2.x(), y, p2.x(), y + sw );
                }
                else if ( ( orientation == Qt::Vertical ) 
                    && ( p1.x() == p2.x() ) )
                {
                    const double sw = d_data->width;

                    const double x = p1.x() - sw / 2;
                    QwtPainter::drawLine( painter,
                        x, p1.y(), x + sw, p1.y() );
                    QwtPainter::drawLine( painter,
                        x, p2.y(), x + sw, p2.y() );
                }
                else
                {
                    const double sw = d_data->width;

                    const double dx = p2.x() - p1.x();
                    const double dy = p2.y() - p1.y();
                    const double angle = qAtan2( dy, dx ) + M_PI_2;
                    double dw2 = sw / 2.0;

                    const double cx = qFastCos( angle ) * dw2;
                    const double sy = qFastSin( angle ) * dw2;

                    QwtPainter::drawLine( painter,
                        p1.x() - cx, p1.y() - sy,
                        p1.x() + cx, p1.y() + sy );
                    QwtPainter::drawLine( painter,
                        p2.x() - cx, p2.y() - sy,
                        p2.x() + cx, p2.y() + sy );
                }
            }
            break;
        }
        case QwtIntervalSymbol::Box:
        {
            if ( d_data->width <= pw )
            {
                QwtPainter::drawLine( painter, p1, p2 );
            }
            else
            {
                if ( ( orientation == Qt::Horizontal ) 
                    && ( p1.y() == p2.y() ) )
                {
                    const double sw = d_data->width;

                    const double y = p1.y() - d_data->width / 2;
                    QwtPainter::drawRect( painter,
                        p1.x(), y, p2.x() - p1.x(),  sw );
                }
                else if ( ( orientation == Qt::Vertical )
                    && ( p1.x() == p2.x() ) )
                {
                    const double sw = d_data->width;

                    const double x = p1.x() - d_data->width / 2;
                    QwtPainter::drawRect( painter,
                        x, p1.y(), sw, p2.y() - p1.y() );
                }
                else
                {
                    const double sw = d_data->width;

                    const double dx = p2.x() - p1.x();
                    const double dy = p2.y() - p1.y();
                    const double angle = qAtan2( dy, dx ) + M_PI_2;
                    double dw2 = sw / 2.0;

                    const double cx = qFastCos( angle ) * dw2;
                    const double sy = qFastSin( angle ) * dw2;

                    QPolygonF polygon;
                    polygon += QPointF( p1.x() - cx, p1.y() - sy );
                    polygon += QPointF( p1.x() + cx, p1.y() + sy );
                    polygon += QPointF( p2.x() + cx, p2.y() + sy );
                    polygon += QPointF( p2.x() - cx, p2.y() - sy );

                    QwtPainter::drawPolygon( painter, polygon );
                }
            }
            break;
        }
        default:;
    }
}
예제 #10
0
int QwtScaleDraw::minLabelDist( const QFont &font ) const
{
    if ( !hasComponent( QwtAbstractScaleDraw::Labels ) )
        return 0;

    const QList<double> &ticks = scaleDiv().ticks( QwtScaleDiv::MajorTick );
    if ( ticks.isEmpty() )
        return 0;

    const QFontMetrics fm( font );

    const bool vertical = ( orientation() == Qt::Vertical );

    QRectF bRect1;
    QRectF bRect2 = labelRect( font, ticks[0] );
    if ( vertical )
    {
        bRect2.setRect( -bRect2.bottom(), 0.0, bRect2.height(), bRect2.width() );
    }

    double maxDist = 0.0;

    for ( int i = 1; i < ticks.count(); i++ )
    {
        bRect1 = bRect2;
        bRect2 = labelRect( font, ticks[i] );
        if ( vertical )
        {
            bRect2.setRect( -bRect2.bottom(), 0.0,
                            bRect2.height(), bRect2.width() );
        }

        double dist = fm.leading(); // space between the labels
        if ( bRect1.right() > 0 )
            dist += bRect1.right();
        if ( bRect2.left() < 0 )
            dist += -bRect2.left();

        if ( dist > maxDist )
            maxDist = dist;
    }

    double angle = qwtRadians( labelRotation() );
    if ( vertical )
        angle += M_PI / 2;

    const double sinA = qFastSin( angle ); // qreal -> double
    if ( qFuzzyCompare( sinA + 1.0, 1.0 ) )
        return qCeil( maxDist );

    const int fmHeight = fm.ascent() - 2;

    // The distance we need until there is
    // the height of the label font. This height is needed
    // for the neighbored label.

    double labelDist = fmHeight / qFastSin( angle ) * qFastCos( angle );
    if ( labelDist < 0 )
        labelDist = -labelDist;

    // For text orientations close to the scale orientation

    if ( labelDist > maxDist )
        labelDist = maxDist;

    // For text orientations close to the opposite of the
    // scale orientation

    if ( labelDist < fmHeight )
        labelDist = fmHeight;

    return qCeil( labelDist );
}
예제 #11
0
//------------------------------------------------------------------------------
QGLBuilder&  operator << ( QGLBuilder& builder, const QGLEllipsoid& ellipsoid )
{
   // Determine the number of slices and stacks to generate.
   static int const numberOfSlicesForSubdivisionDepth[] = { 8, 8, 16, 16, 32, 32, 64, 64, 128, 128 };
   static int const numberOfStacksForSubdivisionDepth[] = { 4, 8,  8, 16, 16, 32, 32, 64,  64, 128 };
   const unsigned int numberOfSlices = numberOfSlicesForSubdivisionDepth[ ellipsoid.GetSubdivisionDepth() - 1 ];
   const unsigned int numberOfStacks = numberOfStacksForSubdivisionDepth[ ellipsoid.GetSubdivisionDepth() - 1 ];

   // Precompute sin/cos values for the slices.
   const unsigned int maxSlices = 128 + 1;
   const unsigned int maxStacks = 128 + 1;
   qreal sliceSin[ maxSlices ];
   qreal sliceCos[ maxSlices ];
   for( unsigned int slice = 0;  slice < numberOfSlices;  ++slice )
   {
       const qreal angle = 2 * M_PI * (numberOfSlices - 1 - slice) / numberOfSlices;
       sliceSin[slice] = qFastSin(angle);
       sliceCos[slice] = qFastCos(angle);
   }
   // Join first and last slice.
   sliceSin[numberOfSlices] = sliceSin[0];
   sliceCos[numberOfSlices] = sliceCos[0];


   // Precompute sin/cos values for the stacks.
   qreal stackSin[ maxStacks ];
   qreal stackCos[ maxStacks ];
   for( unsigned int stack = 0;  stack <= numberOfStacks;  ++stack )
   {
       // Efficiently handle end-points which also ensure geometry comes to a point at the poles (no round-off).
       if(      stack == 0 )               { stackSin[stack] = 0.0f;  stackCos[stack] =  1.0f; }
       else if( stack == numberOfStacks )  { stackSin[stack] = 0.0f;  stackCos[stack] = -1.0f; }
       else
       {
          const qreal angle = M_PI * stack / numberOfStacks;
          stackSin[stack] = qFastSin(angle);
          stackCos[stack] = qFastCos(angle);
       }
   }

   // Half the dimensions of the ellipsoid for calculations below (centroid of ellipsoid is 0, 0, 0.)
   const qreal xRadius = 0.5 * ellipsoid.GetXDiameter();
   const qreal yRadius = 0.5 * ellipsoid.GetYDiameter();
   const qreal zRadius = 0.5 * ellipsoid.GetZDiameter();
   const qreal oneOverXRadiusSquared = 1.0 / (xRadius * xRadius);
   const qreal oneOverYRadiusSquared = 1.0 / (yRadius * yRadius);
   const qreal oneOverZRadiusSquared = 1.0 / (zRadius * zRadius);


   // Create the stacks.
   for( unsigned int stack = 0;  stack < numberOfStacks;  ++stack )
   {
      QGeometryData quadStrip;
      for( unsigned int slice = 0;  slice <= numberOfSlices; ++slice )
      {
          // Equation for ellipsoid surface is x^2/xRadius^2 + y^2/yRadius^2 + z^2/zRadius^2 = 1
          // Location of vertices can be specified in terms of "polar coordinates".
          const qreal nextx = xRadius * stackSin[stack+1] * sliceSin[slice];
          const qreal nexty = yRadius * stackSin[stack+1] * sliceCos[slice];
          const qreal nextz = zRadius * stackCos[stack+1];
          quadStrip.appendVertex( QVector3D( nextx, nexty, nextz) );

          // Equation for ellipsoid surface is  Surface = x^2/xRadius^2 + y^2/yRadius^2 + z^2/zRadius^2 - 1
          // Gradient for ellipsoid is  x/xRadius^2*Nx>  +  y/yRadius^2*Ny>  +  z/zRadius^2*Nz>
          // Gradient for sphere simplifies to  x*Nx> + y*Ny> + z*Nz>
          // const qreal nextGradientx =  stackSin[stack+1] * sliceSin[slice];
          // const qreal nextGradienty =  stackSin[stack+1] * sliceCos[slice];
          // const qreal nextGradientz =  stackCos[stack+1];
          const qreal nextGradientx = nextx * oneOverXRadiusSquared;
          const qreal nextGradienty = nexty * oneOverYRadiusSquared;
          const qreal nextGradientz = nextz * oneOverZRadiusSquared;
          const qreal nextGradientMagSquared = nextGradientx * nextGradientx + nextGradienty * nextGradienty + nextGradientz * nextGradientz;
          const qreal oneOverNextGradientMagnitude = 1.0 / sqrt( nextGradientMagSquared );
          quadStrip.appendNormal( oneOverNextGradientMagnitude * QVector3D( nextGradientx,  nextGradienty, nextGradientz ) );
          quadStrip.appendTexCoord( QVector2D(1.0f - qreal(slice) / numberOfSlices, 1.0f - qreal(stack + 1) / numberOfStacks) );

          const qreal x = xRadius * stackSin[stack] * sliceSin[slice];
          const qreal y = yRadius * stackSin[stack] * sliceCos[slice];
          const qreal z = zRadius * stackCos[stack];
          quadStrip.appendVertex( QVector3D( x, y, z) );

          // const qreal gradientx =  stackSin[stack] * sliceSin[slice];
          // const qreal gradienty =  stackSin[stack] * sliceCos[slice];
          // const qreal gradientz =  stackCos[stack];
          const qreal gradientx = x * oneOverXRadiusSquared;
          const qreal gradienty = y * oneOverYRadiusSquared;
          const qreal gradientz = z * oneOverZRadiusSquared;
          const qreal gradientMagSquared = gradientx * gradientx + gradienty * gradienty + gradientz * gradientz;
          const qreal oneOverGradientMagnitude = 1.0 / sqrt( gradientMagSquared );
          quadStrip.appendNormal( oneOverGradientMagnitude * QVector3D(  gradientx, gradienty, gradientz) );
          quadStrip.appendTexCoord( QVector2D(1.0f - qreal(slice) / numberOfSlices,  1.0f - qreal(stack) / numberOfStacks) );
      }

      // The quad strip stretches from pole to pole.
      builder.addQuadStrip( quadStrip );
   }


   return builder;
}