Пример #1
0
 internal EllipseIterator(Ellipse e, AffineTransform at)
 {
     _x = e.GetX();
     _y = e.GetY();
     _w = e.GetWidth();
     _h = e.GetHeight();
     _affine = at;
     if (_w < 0 || _h < 0)
     {
         _index = 6;
     }
 }
Пример #2
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Constructor
  * @param r
  * @param at
  */
 internal RectIterator(Rectangle r, AffineTransform at)
 {
     _x = r.GetX();
     _y = r.GetY();
     _w = r.GetWidth();
     _h = r.GetHeight();
     _affine = at;
     if (_w < 0 || _h < 0)
     {
         _index = 6;
     }
 }
Пример #3
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 internal ArcIterator(Arc a, AffineTransform at)
 {
     _w = a.GetWidth() / 2.0;
     _h = a.GetHeight() / 2.0;
     _x = a.GetX() + _w;
     _y = a.GetY() + _h;
     _angStRad = -MathEx.ToRadians(a.GetAngleStart());
     _affine = at;
     double ext = -a.GetAngleExtent();
     if (ext >= 360.0 || ext <= -360)
     {
         _arcSegs = 4;
         _increment = Math.PI / 2;
         // btan(Math.PI / 2);
         _cv = 0.5522847498307933;
         if (ext < 0)
         {
             _increment = -_increment;
             _cv = -_cv;
         }
     }
     else
     {
         _arcSegs = (int)MathEx.Ceil(MathEx.Abs(ext) / 90.0);
         _increment = MathEx.ToRadians(ext / _arcSegs);
         _cv = Btan(_increment);
         if (_cv == 0)
         {
             _arcSegs = 0;
         }
     }
     switch (a.GetArcType())
     {
         case Arc.OPEN:
             _lineSegs = 0;
             break;
         case Arc.CHORD:
             _lineSegs = 1;
             break;
         case Arc.PIE:
             _lineSegs = 2;
             break;
     }
     if (_w < 0 || _h < 0)
     {
         _arcSegs = _lineSegs = -1;
     }
 }
Пример #4
0
 internal static AffineTransform ToMatrix(MatrixFP matrixFP)
 {
     if (matrixFP == null)
     {
         return null;
     }
     if (matrixFP.IsIdentity())
     {
         return new AffineTransform();
     }
     AffineTransform matrix = new AffineTransform(SingleFP.ToDouble(matrixFP.ScaleX),
             SingleFP.ToDouble(matrixFP.RotateX),
             SingleFP.ToDouble(matrixFP.RotateY),
             SingleFP.ToDouble(matrixFP.ScaleY),
             SingleFP.ToDouble(matrixFP.TranslateX),
             SingleFP.ToDouble(matrixFP.TranslateY));
     return matrix;
 }
Пример #5
0
        internal static MatrixFP ToMatrixFP(AffineTransform matrix)
        {
            if (matrix == null)
            {
                return null;
            }
            if (matrix.IsIdentity())
            {
                return MatrixFP.Identity;
            }

            MatrixFP matrixFP = new MatrixFP(SingleFP.FromDouble(matrix.GetScaleX()),
                    SingleFP.FromDouble(matrix.GetScaleY()),
                    SingleFP.FromDouble(matrix.GetShearX()),
                    SingleFP.FromDouble(matrix.GetShearY()),
                    SingleFP.FromDouble(matrix.GetTranslateX()),
                    SingleFP.FromDouble(matrix.GetTranslateY()));
            return matrixFP;
        }
Пример #6
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns an iteration object that defines the boundary of the
  * shape of this <code>QuadCurve</code>.
  * The iterator for this class is not multi-threaded safe,
  * which means that this <code>QuadCurve</code> class does not
  * guarantee that modifications to the geometry of this
  * <code>QuadCurve</code> object do not affect any iterations of
  * that geometry that are already in process.
  * @param at an optional {@link AffineTransform} to apply to the
  *		shape boundary
  * @return a {@link PathIterator} object that defines the boundary
  *		of the shape.
  */
 public PathIterator GetPathIterator(AffineTransform at)
 {
     return new QuadIterator(this, at);
 }
Пример #7
0
 public AreaIterator(ArrayList curves, AffineTransform at)
 {
     _curves = curves;
     _transform = at;
     if (curves.Count >= 1)
     {
         _thiscurve = (Curve)curves[0];
     }
 }
Пример #8
0
 internal RoundRectIterator(RoundRectangle rr, AffineTransform at)
 {
     _x = rr.GetX();
     _y = rr.GetY();
     _w = rr.GetWidth();
     _h = rr.GetHeight();
     _aw = Math.Min(_w, Math.Abs(rr.GetArcWidth()));
     _ah = Math.Min(_h, Math.Abs(rr.GetArcHeight()));
     _affine = at;
     if (_aw < 0 || _ah < 0)
     {
         // Don't draw anything...
         _index = CTRLPTS.Length;
     }
 }
Пример #9
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns an iteration object that defines the boundary of the
  * arc.
  * This iterator is multithread safe.
  * <code>Arc</code> guarantees that
  * modifications to the geometry of the arc
  * do not affect any iterations of that geometry that
  * are already in process.
  *
  * @param at an optional <CODE>AffineTransform</CODE> to be applied
  * to the coordinates as they are returned in the iteration, or null
  * if the untransformed coordinates are desired.
  *
  * @return A <CODE>IPathIterator</CODE> that defines the arc's boundary.
  */
 public override PathIterator GetPathIterator(AffineTransform at)
 {
     return new ArcIterator(this, at);
 }
Пример #10
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Transforms the geometry of this <code>Area</code> using the specified
  * {@link AffineTransform}.  The geometry is transformed in place, which
  * permanently changes the enclosed area defined by this object.
  * @param t  the transformation used to transform the area
  * @throws NullPointerException if <code>t</code> is null
  */
 public void Transform(AffineTransform t)
 {
     if (t == null)
     {
         throw new NullReferenceException("transform must not be null");
     }
     // REMIND: A simpler operation can be performed for some types
     // of transform.
     _curves = PathToCurves(GetPathIterator(t));
     InvalidateBounds();
 }
Пример #11
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns a transform representing a translation transformation.
  * The matrix representing the returned transform is:
  * <pre>
  *		[   1    0    tx  ]
  *		[   0    1    ty  ]
  *		[   0    0    1   ]
  * </pre>
  * @param tx the distance by which coordinates are translated in the
  * X axis direction
  * @param ty the distance by which coordinates are translated in the
  * Y axis direction
  * @return an <code>AffineTransform</code> object that represents a
  * 	translation transformation, created with the specified vector.
  */
 public static AffineTransform GetTranslateInstance(double tx, double ty)
 {
     var trans = new AffineTransform();
     trans.SetToTranslation(tx, ty);
     return trans;
 }
Пример #12
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns a transform representing a scaling transformation.
  * The matrix representing the returned transform is:
  * <pre>
  *		[   sx   0    0   ]
  *		[   0    sy   0   ]
  *		[   0    0    1   ]
  * </pre>
  * @param sx the factor by which coordinates are scaled along the
  * X axis direction
  * @param sy the factor by which coordinates are scaled along the
  * Y axis direction
  * @return an <code>AffineTransform</code> object that scales
  *	coordinates by the specified factors.
  */
 public static AffineTransform GetScaleInstance(double sx, double sy)
 {
     var tx = new AffineTransform();
     tx.SetToScale(sx, sy);
     return tx;
 }
Пример #13
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns a transform representing a rotation transformation.
  * The matrix representing the returned transform is:
  * <pre>
  *		[   Cos(theta)    -Sin(theta)    0   ]
  *		[   Sin(theta)     Cos(theta)    0   ]
  *		[       0              0         1   ]
  * </pre>
  * Rotating by a positive angle theta rotates points on the positive
  * X axis toward the positive Y axis.
  * also the discussion of
  * <a href="#quadrantapproximation">Handling 90-Degree Rotations</a>
  * above.
  * @param theta the angle of rotation measured in radians
  * @return an <code>AffineTransform</code> object that is a rotation
  *	transformation, created with the specified angle of rotation.
  */
 public static AffineTransform GetRotateInstance(double theta)
 {
     var tx = new AffineTransform();
     tx.SetToRotation(theta);
     return tx;
 }
Пример #14
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Constructs a new <code>AffineTransform</code> that is a copy of
  * the specified <code>AffineTransform</code> object.
  * @param Tx the <code>AffineTransform</code> object to copy
  */
 public AffineTransform(AffineTransform tx)
 {
     _m00 = tx._m00;
     _m10 = tx._m10;
     _m01 = tx._m01;
     _m11 = tx._m11;
     _m02 = tx._m02;
     _m12 = tx._m12;
     _state = tx._state;
     _type = tx._type;
 }
Пример #15
0
 public abstract PathIterator GetPathIterator(AffineTransform at);
Пример #16
0
 internal QuadIterator(QuadCurve q, AffineTransform at)
 {
     _quad = q;
     _affine = at;
 }
        ////////////////////////////////////////////////////////////////////////////
        //--------------------------------- REVISIONS ------------------------------
        // Date       Name                 Tracking #         Description
        // ---------  -------------------  -------------      ----------------------
        // 15JUN2009  James Shen                 	          Initial Creation
        ////////////////////////////////////////////////////////////////////////////
        /**
         * Constructs a {@code LinearGradientBrush}.
         *
         * @param start the gradient axis start {@code Point} in user space
         * @param end the gradient axis end {@code Point} in user space
         * @param fractions numbers ranging from 0 to 255 specifying the
         *                  distribution of colors along the gradient
         * @param colors array of colors corresponding to each fractional Value
         * @param fillType either {@code NO_CYCLE}, {@code REFLECT},
         *                    or {@code REPEAT}
         * @param gradientTransform transform to apply to the gradient
         *
         * @throws NullPointerException
         * if one of the points is null,
         * or {@code fractions} array is null,
         * or {@code colors} array is null,
         * or {@code cycleMethod} is null,
         * or {@code colorSpace} is null,
         * or {@code gradientTransform} is null
         * @throws IllegalArgumentException
         * if start and end points are the same points,
         * or {@code fractions.length != colors.length},
         * or {@code colors} is less than 2 in size,
         * or a {@code fractions} Value is less than 0.0 or greater than 1.0,
         * or the {@code fractions} are not provided in strictly increasing order
         */
        public LinearGradientBrush(Point start, Point end,
                int[] fractions, Color[] colors,
                AffineTransform gradientTransform, int fillType)
        {
            if (fractions == null)
            {
                throw new NullReferenceException("Fractions array cannot be null");
            }

            if (colors == null)
            {
                throw new NullReferenceException("Colors array cannot be null");
            }

            if (gradientTransform == null)
            {
                throw new NullReferenceException("Gradient transform cannot be " +
                        "null");
            }

            if (fractions.Length != colors.Length)
            {
                throw new ArgumentException("Colors and fractions must " +
                        "have equal size");
            }

            if (colors.Length < 2)
            {
                throw new ArgumentException("User must specify at least " +
                        "2 colors");
            }

            // check that values are in the proper range and progress
            // in increasing order from 0 to 1
            int previousFraction = -255;
            for (int i = 0; i < fractions.Length; i++)
            {
                int currentFraction = fractions[i];
                if (currentFraction < 0 || currentFraction > 255)
                {
                    throw new ArgumentException("Fraction values must " +
                            "be in the range 0 to 255: " +
                            currentFraction);
                }

                if (currentFraction <= previousFraction)
                {
                    throw new ArgumentException("Keyframe fractions " +
                            "must be increasing: " +
                            currentFraction);
                }

                previousFraction = currentFraction;
            }

            // We have to deal with the cases where the first gradient stop is not
            // equal to 0 and/or the last gradient stop is not equal to 1.
            // In both cases, create a new point and replicate the previous
            // extreme point's color.
            bool fixFirst = false;
            bool fixLast = false;
            int len = fractions.Length;
            int off = 0;

            if (fractions[0] != 0)
            {
                // first stop is not equal to zero, fix this condition
                fixFirst = true;
                len++;
                off++;
            }
            if (fractions[fractions.Length - 1] != 255)
            {
                // last stop is not equal to one, fix this condition
                fixLast = true;
                len++;
            }

            this._fractions = new int[len];
            Array.Copy(fractions, 0, this._fractions, off, fractions.Length);
            this._colors = new Color[len];
            Array.Copy(colors, 0, this._colors, off, colors.Length);

            if (fixFirst)
            {
                this._fractions[0] = 0;
                this._colors[0] = colors[0];
            }
            if (fixLast)
            {
                this._fractions[len - 1] = 255;
                this._colors[len - 1] = colors[colors.Length - 1];
            }

            // copy the gradient transform
            this._gradientTransform = new AffineTransform(gradientTransform);

            // determine transparency
            bool opaque = true;
            for (int i = 0; i < colors.Length; i++)
            {
                opaque = opaque && (colors[i].GetAlpha() == 0xff);
            }
            _transparency = opaque ? Color.OPAQUE : Color.TRANSLUCENT;

            // check input parameters
            if (start == null || end == null)
            {
                throw new NullReferenceException("Start and end points must be" +
                        "non-null");
            }

            if (start.Equals(end))
            {
                throw new ArgumentException("Start point cannot equal" +
                        "endpoint");
            }

            // copy the points...
            this._start = new Point(start.GetX(), start.GetY());
            this._end = new Point(end.GetX(), end.GetY());

            Rectangle rectangle = new Rectangle(start, end);
            float dx = start.X - end.X;
            float dy = start.Y - end.Y;
            double angle = MathEx.Atan2(dy, dx);
            int intAngle = SingleFP.FromDouble(angle);
            RectangleFP r = Utils.ToRectangleFP(rectangle);
            _wrappedBrushFP = new LinearGradientBrushFP(r.GetLeft(), r.GetTop(),
                    r.GetRight(), r.GetBottom(),
                    intAngle);
            for (int i = 0; i < colors.Length; i++)
            {
                ((LinearGradientBrushFP)_wrappedBrushFP).SetGradientColor
                        (SingleFP.FromFloat(fractions[i] / 100.0f),
                        colors[i]._value);
            }
            ((LinearGradientBrushFP)_wrappedBrushFP).UpdateGradientTable();
            _wrappedBrushFP.SetMatrix(Utils.ToMatrixFP(gradientTransform));
            _wrappedBrushFP.FillMode = fillType;
        }
 public LinearGradientBrush(Rectangle rect, Color color1, Color color2,
         float angle, int fillType)
 {
     _start = new Point(rect.X, rect.Y);
     _end = new Point(rect.X + rect.Width, rect.Y + rect.Height);
     _gradientTransform = new AffineTransform();
     _fractions = new[] { 0, 100 };
     _colors = new[] { color1, color2 };
     bool opaque = true;
     for (int i = 0; i < _colors.Length; i++)
     {
         opaque = opaque && (_colors[i].GetAlpha() == 0xff);
     }
     _transparency = opaque ? Color.OPAQUE : Color.TRANSLUCENT;
     RectangleFP r = Utils.ToRectangleFP(rect);
     _wrappedBrushFP = new LinearGradientBrushFP(r.GetLeft(), r.GetTop(),
             r.GetRight(), r.GetBottom(),
             MathFP.ToRadians(SingleFP.FromFloat(angle)));
     for (int i = 0; i < _colors.Length; i++)
     {
         ((LinearGradientBrushFP)_wrappedBrushFP)
                 .SetGradientColor(SingleFP.FromFloat(_fractions[i]
                 / 255.0f),
                 _colors[i]._value);
     }
     ((LinearGradientBrushFP)_wrappedBrushFP).UpdateGradientTable();
     _wrappedBrushFP.SetMatrix(Utils.ToMatrixFP(_gradientTransform));
     _wrappedBrushFP.FillMode = fillType;
 }
Пример #19
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Constructor.
  * @param l
  * @param at
  */
 internal LineIterator(Line l, AffineTransform at)
 {
     _line = l;
     _affine = at;
 }
Пример #20
0
 internal CubicIterator(CubicCurve q, AffineTransform at)
 {
     _cubic = q;
     _affine = at;
 }
Пример #21
0
        ////////////////////////////////////////////////////////////////////////////
        //--------------------------------- REVISIONS ------------------------------
        // Date       Name                 Tracking #         Description
        // ---------  -------------------  -------------      ----------------------
        // 13JUN2009  James Shen                 	          Initial Creation
        ////////////////////////////////////////////////////////////////////////////
        /**
         * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
         * this <code>AffineTransform</code> Cx
         * in a less commonly used way such that <code>Tx</code> modifies the
         * coordinate transformation relative to the absolute pixel
         * space rather than relative to the existing user space.
         * Cx is updated to perform the combined transformation.
         * Transforming a point p by the updated transform Cx' is
         * equivalent to first transforming p by the original transform
         * Cx and then transforming the result by
         * <code>Tx</code> like this:
         * Cx'(p) = Tx(Cx(p))
         * In matrix notation, if this transform Cx
         * is represented by the matrix [this] and <code>Tx</code> is
         * represented by the matrix [Tx] then this method does the
         * following:
         * <pre>
         *		[this] = [Tx] x [this]
         * </pre>
         * @param Tx the <code>AffineTransform</code> object to be
         * concatenated with this <code>AffineTransform</code> object.
         */
        public void PreConcatenate(AffineTransform tx)
        {
            double m0;
            double t00, t01, t10, t11;
            int mystate = _state;
            int txstate = tx._state;
            switch ((txstate << HI_SHIFT) | mystate)
            {
                case (HI_IDENTITY | APPLY_IDENTITY):
                case (HI_IDENTITY | APPLY_TRANSLATE):
                case (HI_IDENTITY | APPLY_SCALE):
                case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_IDENTITY | APPLY_SHEAR):
                case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                    // Tx is IDENTITY...
                    return;

                case (HI_TRANSLATE | APPLY_IDENTITY):
                case (HI_TRANSLATE | APPLY_SCALE):
                case (HI_TRANSLATE | APPLY_SHEAR):
                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
                    // Tx is TRANSLATE, this has no TRANSLATE
                    _m02 = tx._m02;
                    _m12 = tx._m12;
                    _state = mystate | APPLY_TRANSLATE;
                    _type |= TYPE_TRANSLATION;
                    return;

                case (HI_TRANSLATE | APPLY_TRANSLATE):
                case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                    // Tx is TRANSLATE, this has one too
                    _m02 = _m02 + tx._m02;
                    _m12 = _m12 + tx._m12;
                    return;

                case (HI_SCALE | APPLY_TRANSLATE):
                case (HI_SCALE | APPLY_IDENTITY):
                    // Only these two existing states need a new state
                    _state = mystate | APPLY_SCALE;
                    t00 = tx._m00;
                    t11 = tx._m11;
                    if ((mystate & APPLY_SHEAR) != 0)
                    {
                        _m01 = _m01 * t00;
                        _m10 = _m10 * t11;
                        if ((mystate & APPLY_SCALE) != 0)
                        {
                            _m00 = _m00 * t00;
                            _m11 = _m11 * t11;
                        }
                    }
                    else
                    {
                        _m00 = _m00 * t00;
                        _m11 = _m11 * t11;
                    }
                    if ((mystate & APPLY_TRANSLATE) != 0)
                    {
                        _m02 = _m02 * t00;
                        _m12 = _m12 * t11;
                    }
                    _type = TYPE_UNKNOWN;
                    return;
                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
                case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
                case (HI_SCALE | APPLY_SHEAR):
                case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_SCALE | APPLY_SCALE):
                    // Tx is SCALE, this is anything
                    t00 = tx._m00;
                    t11 = tx._m11;
                    if ((mystate & APPLY_SHEAR) != 0)
                    {
                        _m01 = _m01 * t00;
                        _m10 = _m10 * t11;
                        if ((mystate & APPLY_SCALE) != 0)
                        {
                            _m00 = _m00 * t00;
                            _m11 = _m11 * t11;
                        }
                    }
                    else
                    {
                        _m00 = _m00 * t00;
                        _m11 = _m11 * t11;
                    }
                    if ((mystate & APPLY_TRANSLATE) != 0)
                    {
                        _m02 = _m02 * t00;
                        _m12 = _m12 * t11;
                    }
                    _type = TYPE_UNKNOWN;
                    return;
                case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
                case (HI_SHEAR | APPLY_SHEAR):
                    mystate = mystate | APPLY_SCALE;
                    _state = mystate ^ APPLY_SHEAR;
                    // Tx is SHEAR, this is anything
                    t01 = tx._m01;
                    t10 = tx._m10;

                    m0 = _m00;
                    _m00 = _m10 * t01;
                    _m10 = m0 * t10;

                    m0 = _m01;
                    _m01 = _m11 * t01;
                    _m11 = m0 * t10;

                    m0 = _m02;
                    _m02 = _m12 * t01;
                    _m12 = m0 * t10;
                    _type = TYPE_UNKNOWN;
                    return;
                case (HI_SHEAR | APPLY_TRANSLATE):
                case (HI_SHEAR | APPLY_IDENTITY):
                case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_SHEAR | APPLY_SCALE):
                    _state = mystate ^ APPLY_SHEAR;
                    // Tx is SHEAR, this is anything
                    t01 = tx._m01;
                    t10 = tx._m10;

                    m0 = _m00;
                    _m00 = _m10 * t01;
                    _m10 = m0 * t10;

                    m0 = _m01;
                    _m01 = _m11 * t01;
                    _m11 = m0 * t10;

                    m0 = _m02;
                    _m02 = _m12 * t01;
                    _m12 = m0 * t10;
                    _type = TYPE_UNKNOWN;
                    return;
                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
                    // Tx is SHEAR, this is anything
                    t01 = tx._m01;
                    t10 = tx._m10;

                    m0 = _m00;
                    _m00 = _m10 * t01;
                    _m10 = m0 * t10;

                    m0 = _m01;
                    _m01 = _m11 * t01;
                    _m11 = m0 * t10;

                    m0 = _m02;
                    _m02 = _m12 * t01;
                    _m12 = m0 * t10;
                    _type = TYPE_UNKNOWN;
                    return;
            }
            // If Tx has more than one attribute, it is not worth optimizing
            // all of those cases...
            t00 = tx._m00; t01 = tx._m01; double t02 = tx._m02;
            t10 = tx._m10; t11 = tx._m11; double t12 = tx._m12;
            switch (mystate)
            {
                default:
                    StateError();
                    break;
                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                    m0 = _m02;
                    double m1 = _m12;
                    t02 += m0 * t00 + m1 * t01;
                    t12 += m0 * t10 + m1 * t11;

                    _m02 = t02;
                    _m12 = t12;

                    m0 = _m00;
                    m1 = _m10;
                    _m00 = m0 * t00 + m1 * t01;
                    _m10 = m0 * t10 + m1 * t11;

                    m0 = _m01;
                    m1 = _m11;
                    _m01 = m0 * t00 + m1 * t01;
                    _m11 = m0 * t10 + m1 * t11;
                    break;
                case (APPLY_SHEAR | APPLY_SCALE):
                    _m02 = t02;
                    _m12 = t12;

                    m0 = _m00;
                    m1 = _m10;
                    _m00 = m0 * t00 + m1 * t01;
                    _m10 = m0 * t10 + m1 * t11;

                    m0 = _m01;
                    m1 = _m11;
                    _m01 = m0 * t00 + m1 * t01;
                    _m11 = m0 * t10 + m1 * t11;
                    break;

                case (APPLY_SHEAR | APPLY_TRANSLATE):
                    m0 = _m02;
                    m1 = _m12;
                    t02 += m0 * t00 + m1 * t01;
                    t12 += m0 * t10 + m1 * t11;

                    _m02 = t02;
                    _m12 = t12;

                    m0 = _m10;
                    _m00 = m0 * t01;
                    _m10 = m0 * t11;

                    m0 = _m01;
                    _m01 = m0 * t00;
                    _m11 = m0 * t10;
                    break;
                case (APPLY_SHEAR):
                    _m02 = t02;
                    _m12 = t12;

                    m0 = _m10;
                    _m00 = m0 * t01;
                    _m10 = m0 * t11;

                    m0 = _m01;
                    _m01 = m0 * t00;
                    _m11 = m0 * t10;
                    break;

                case (APPLY_SCALE | APPLY_TRANSLATE):
                    m0 = _m02;
                    m1 = _m12;
                    t02 += m0 * t00 + m1 * t01;
                    t12 += m0 * t10 + m1 * t11;

                    _m02 = t02;
                    _m12 = t12;

                    m0 = _m00;
                    _m00 = m0 * t00;
                    _m10 = m0 * t10;

                    m0 = _m11;
                    _m01 = m0 * t01;
                    _m11 = m0 * t11;
                    break;
                case (APPLY_SCALE):
                    _m02 = t02;
                    _m12 = t12;

                    m0 = _m00;
                    _m00 = m0 * t00;
                    _m10 = m0 * t10;

                    m0 = _m11;
                    _m01 = m0 * t01;
                    _m11 = m0 * t11;
                    break;

                case (APPLY_TRANSLATE):
                    m0 = _m02;
                    m1 = _m12;
                    t02 += m0 * t00 + m1 * t01;
                    t12 += m0 * t10 + m1 * t11;

                    _m02 = t02;
                    _m12 = t12;

                    _m00 = t00;
                    _m10 = t10;

                    _m01 = t01;
                    _m11 = t11;

                    _state = mystate | txstate;
                    _type = TYPE_UNKNOWN;
                    return;
                case (APPLY_IDENTITY):
                    _m02 = t02;
                    _m12 = t12;

                    _m00 = t00;
                    _m10 = t10;

                    _m01 = t01;
                    _m11 = t11;

                    _state = mystate | txstate;
                    _type = TYPE_UNKNOWN;
                    return;
            }
            UpdateState();
        }
Пример #22
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns an iteration object that defines the boundary of the
  * flattened shape of this <code>QuadCurve</code>.
  * The iterator for this class is not multi-threaded safe,
  * which means that this <code>QuadCurve</code> class does not
  * guarantee that modifications to the geometry of this
  * <code>QuadCurve</code> object do not affect any iterations of
  * that geometry that are already in process.
  * @param at an optional <code>AffineTransform</code> to apply
  *		to the boundary of the shape
  * @param flatness the maximum distance that the control points for a
  *		subdivided curve can be with respect to a line connecting
  * 		the end points of this curve before this curve is
  *		replaced by a straight line connecting the end points.
  * @return a <code>PathIterator</code> object that defines the
  *		flattened boundary of the shape.
  */
 public PathIterator GetPathIterator(AffineTransform at, int flatness)
 {
     return new FlatteningPathIterator(GetPathIterator(at), flatness);
 }
Пример #23
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns a transform that rotates coordinates by the specified
  * number of quadrants around the specified anchor point.
  * This operation is equivalent to calling:
  * <pre>
  *     AffineTransform.getRotateInstance(numquadrants * Math.PI / 2.0,
  *                                       anchorx, anchory);
  * </pre>
  * Rotating by a positive number of quadrants rotates points on
  * the positive X axis toward the positive Y axis.
  *
  * @param numquadrants the number of 90 degree arcs to rotate by
  * @param anchorx the X coordinate of the rotation anchor point
  * @param anchory the Y coordinate of the rotation anchor point
  * @return an <code>AffineTransform</code> object that rotates
  *	coordinates by the specified number of quadrants around the
  *  specified anchor point.
  */
 public static AffineTransform GetQuadrantRotateInstance(int numquadrants,
                             double anchorx,
                             double anchory)
 {
     var tx = new AffineTransform();
     tx.SetToQuadrantRotation(numquadrants, anchorx, anchory);
     return tx;
 }
Пример #24
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns an iterator object that iterates along the boundary of this
  * <code>Polygon</code> and provides access to the geometry
  * of the outline of this <code>Polygon</code>.  An optional
  * {@link AffineTransform} can be specified so that the coordinates
  * returned in the iteration are transformed accordingly.
  * @param at an optional <code>AffineTransform</code> to be applied to the
  * 		coordinates as they are returned in the iteration, or
  *		<code>null</code> if untransformed coordinates are desired
  * @return a {@link IPathIterator} object that provides access to the
  *		geometry of this <code>Polygon</code>.
  */
 public PathIterator GetPathIterator(AffineTransform at)
 {
     return new PolygonPathIterator(this, at);
 }
Пример #25
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns a transform that rotates coordinates around an anchor
  * point accordinate to a rotation vector.
  * All coordinates rotate about the specified anchor coordinates
  * by the same amount.
  * The amount of rotation is such that coordinates along the former
  * positive X axis will subsequently align with the vector pointing
  * from the origin to the specified vector coordinates.
  * If both <code>vecx</code> and <code>vecy</code> are 0.0,
  * an identity transform is returned.
  * This operation is equivalent to calling:
  * <pre>
  *     AffineTransform.getRotateInstance(Math.Atan2(vecy, vecx),
  *                                       anchorx, anchory);
  * </pre>
  *
  * @param vecx the X coordinate of the rotation vector
  * @param vecy the Y coordinate of the rotation vector
  * @param anchorx the X coordinate of the rotation anchor point
  * @param anchory the Y coordinate of the rotation anchor point
  * @return an <code>AffineTransform</code> object that rotates
  *	coordinates around the specified point according to the
  *  specified rotation vector.
  */
 public static AffineTransform GetRotateInstance(double vecx,
                         double vecy,
                         double anchorx,
                         double anchory)
 {
     var tx = new AffineTransform();
     tx.SetToRotation(vecx, vecy, anchorx, anchory);
     return tx;
 }
Пример #26
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns an iterator object that iterates along the boundary of
  * the <code>IShape</code> and provides access to the geometry of the
  * outline of the <code>IShape</code>.  Only SEG_MOVETO, SEG_LINETO, and
  * SEG_CLOSE point types are returned by the iterator.
  * Since polygons are already flat, the <code>flatness</code> parameter
  * is ignored.  An optional <code>AffineTransform</code> can be specified
  * in which case the coordinates returned in the iteration are transformed
  * accordingly.
  * @param at an optional <code>AffineTransform</code> to be applied to the
  * 		coordinates as they are returned in the iteration, or
  *		<code>null</code> if untransformed coordinates are desired
  * @param flatness the maximum amount that the control points
  * 		for a given curve can vary from colinear before a subdivided
  *		curve is replaced by a straight line connecting the
  * 		endpoints.  Since polygons are already flat the
  * 		<code>flatness</code> parameter is ignored.
  * @return a <code>IPathIterator</code> object that provides access to the
  * 		<code>IShape</code> object's geometry.
  */
 public PathIterator GetPathIterator(AffineTransform at, int flatness)
 {
     return GetPathIterator(at);
 }
Пример #27
0
 ////////////////////////////////////////////////////////////////////////////
 //--------------------------------- REVISIONS ------------------------------
 // Date       Name                 Tracking #         Description
 // ---------  -------------------  -------------      ----------------------
 // 13JUN2009  James Shen                 	          Initial Creation
 ////////////////////////////////////////////////////////////////////////////
 /**
  * Returns a transform representing a shearing transformation.
  * The matrix representing the returned transform is:
  * <pre>
  *		[   1   shx   0   ]
  *		[  shy   1    0   ]
  *		[   0    0    1   ]
  * </pre>
  * @param shx the multiplier by which coordinates are shifted in the
  * direction of the positive X axis as a factor of their Y coordinate
  * @param shy the multiplier by which coordinates are shifted in the
  * direction of the positive Y axis as a factor of their X coordinate
  * @return an <code>AffineTransform</code> object that shears
  *	coordinates by the specified multipliers.
  */
 public static AffineTransform GetShearInstance(double shx, double shy)
 {
     var tx = new AffineTransform();
     tx.SetToShear(shx, shy);
     return tx;
 }
Пример #28
0
 public PolygonPathIterator(Polygon pg, AffineTransform at)
 {
     poly = pg;
     transform = at;
     if (pg.NumOfNpoints == 0)
     {
         // Prevent a spurious SEG_CLOSE segment
         index = 1;
     }
 }
Пример #29
0
        ////////////////////////////////////////////////////////////////////////////
        //--------------------------------- REVISIONS ------------------------------
        // Date       Name                 Tracking #         Description
        // ---------  -------------------  -------------      ----------------------
        // 13JUN2009  James Shen                 	          Initial Creation
        ////////////////////////////////////////////////////////////////////////////
        /**
         * Concatenates an <code>AffineTransform</code> <code>Tx</code> to
         * this <code>AffineTransform</code> Cx in the most commonly useful
         * way to provide a new user space
         * that is mapped to the former user space by <code>Tx</code>.
         * Cx is updated to perform the combined transformation.
         * Transforming a point p by the updated transform Cx' is
         * equivalent to first transforming p by <code>Tx</code> and then
         * transforming the result by the original transform Cx like this:
         * Cx'(p) = Cx(Tx(p))
         * In matrix notation, if this transform Cx is
         * represented by the matrix [this] and <code>Tx</code> is represented
         * by the matrix [Tx] then this method does the following:
         * <pre>
         *		[this] = [this] x [Tx]
         * </pre>
         * @param Tx the <code>AffineTransform</code> object to be
         * concatenated with this <code>AffineTransform</code> object.
         */
        public void Concatenate(AffineTransform tx)
        {
            double m0, m1;
            double t01, t10;
            int mystate = _state;
            int txstate = tx._state;
            switch ((txstate << HI_SHIFT) | mystate)
            {

                /* ---------- Tx == IDENTITY cases ---------- */
                case (HI_IDENTITY | APPLY_IDENTITY):
                case (HI_IDENTITY | APPLY_TRANSLATE):
                case (HI_IDENTITY | APPLY_SCALE):
                case (HI_IDENTITY | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_IDENTITY | APPLY_SHEAR):
                case (HI_IDENTITY | APPLY_SHEAR | APPLY_TRANSLATE):
                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE):
                case (HI_IDENTITY | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                    return;

                /* ---------- this == IDENTITY cases ---------- */
                case (HI_SHEAR | HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
                    _m01 = tx._m01;
                    _m10 = tx._m10;
                    _m00 = tx._m00;
                    _m11 = tx._m11;
                    _m02 = tx._m02;
                    _m12 = tx._m12;
                    _state = txstate;
                    _type = tx._type;
                    return;

                case (HI_SCALE | HI_TRANSLATE | APPLY_IDENTITY):
                    _m00 = tx._m00;
                    _m11 = tx._m11;
                    _m02 = tx._m02;
                    _m12 = tx._m12;
                    _state = txstate;
                    _type = tx._type;
                    return;
                case (HI_TRANSLATE | APPLY_IDENTITY):
                    _m02 = tx._m02;
                    _m12 = tx._m12;
                    _state = txstate;
                    _type = tx._type;
                    return;
                case (HI_SHEAR | HI_SCALE | APPLY_IDENTITY):
                    _m01 = tx._m01;
                    _m10 = tx._m10;
                    _m00 = tx._m00;
                    _m11 = tx._m11;
                    _state = txstate;
                    _type = tx._type;
                    return;
                case (HI_SCALE | APPLY_IDENTITY):
                    _m00 = tx._m00;
                    _m11 = tx._m11;
                    _state = txstate;
                    _type = tx._type;
                    return;
                case (HI_SHEAR | HI_TRANSLATE | APPLY_IDENTITY):
                    _m02 = tx._m02;
                    _m12 = tx._m12;
                    _m01 = tx._m01;
                    _m10 = tx._m10;
                    _m00 = _m11 = 0.0;
                    _state = txstate;
                    _type = tx._type;
                    return;
                case (HI_SHEAR | APPLY_IDENTITY):
                    _m01 = tx._m01;
                    _m10 = tx._m10;
                    _m00 = _m11 = 0.0;
                    _state = txstate;
                    _type = tx._type;
                    return;

                /* ---------- Tx == TRANSLATE cases ---------- */
                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_SCALE):
                case (HI_TRANSLATE | APPLY_SHEAR | APPLY_TRANSLATE):
                case (HI_TRANSLATE | APPLY_SHEAR):
                case (HI_TRANSLATE | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_TRANSLATE | APPLY_SCALE):
                case (HI_TRANSLATE | APPLY_TRANSLATE):
                    Translate(tx._m02, tx._m12);
                    return;

                /* ---------- Tx == SCALE cases ---------- */
                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_SCALE | APPLY_SHEAR | APPLY_SCALE):
                case (HI_SCALE | APPLY_SHEAR | APPLY_TRANSLATE):
                case (HI_SCALE | APPLY_SHEAR):
                case (HI_SCALE | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_SCALE | APPLY_SCALE):
                case (HI_SCALE | APPLY_TRANSLATE):
                    Scale(tx._m00, tx._m11);
                    return;

                /* ---------- Tx == SHEAR cases ---------- */
                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_SHEAR | APPLY_SHEAR | APPLY_SCALE):
                    t01 = tx._m01; t10 = tx._m10;
                    m0 = _m00;
                    _m00 = _m01 * t10;
                    _m01 = m0 * t01;
                    m0 = _m10;
                    _m10 = _m11 * t10;
                    _m11 = m0 * t01;
                    _type = TYPE_UNKNOWN;
                    return;
                case (HI_SHEAR | APPLY_SHEAR | APPLY_TRANSLATE):
                case (HI_SHEAR | APPLY_SHEAR):
                    _m00 = _m01 * tx._m10;
                    _m01 = 0.0;
                    _m11 = _m10 * tx._m01;
                    _m10 = 0.0;
                    _state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
                    _type = TYPE_UNKNOWN;
                    return;
                case (HI_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                case (HI_SHEAR | APPLY_SCALE):
                    _m01 = _m00 * tx._m01;
                    _m00 = 0.0;
                    _m10 = _m11 * tx._m10;
                    _m11 = 0.0;
                    _state = mystate ^ (APPLY_SHEAR | APPLY_SCALE);
                    _type = TYPE_UNKNOWN;
                    return;
                case (HI_SHEAR | APPLY_TRANSLATE):
                    _m00 = 0.0;
                    _m01 = tx._m01;
                    _m10 = tx._m10;
                    _m11 = 0.0;
                    _state = APPLY_TRANSLATE | APPLY_SHEAR;
                    _type = TYPE_UNKNOWN;
                    return;
            }
            // If Tx has more than one attribute, it is not worth optimizing
            // all of those cases...
            double t00 = tx._m00; t01 = tx._m01; double t02 = tx._m02;
            t10 = tx._m10; double t11 = tx._m11; double t12 = tx._m12;
            switch (mystate)
            {
                default:
                    StateError();
                    return;
                case (APPLY_SHEAR | APPLY_SCALE):
                    _state = mystate | txstate;
                    m0 = _m00;
                    m1 = _m01;
                    _m00 = t00 * m0 + t10 * m1;
                    _m01 = t01 * m0 + t11 * m1;
                    _m02 += t02 * m0 + t12 * m1;

                    m0 = _m10;
                    m1 = _m11;
                    _m10 = t00 * m0 + t10 * m1;
                    _m11 = t01 * m0 + t11 * m1;
                    _m12 += t02 * m0 + t12 * m1;
                    _type = TYPE_UNKNOWN;
                    return;
                case (APPLY_SHEAR | APPLY_SCALE | APPLY_TRANSLATE):
                    m0 = _m00;
                    m1 = _m01;
                    _m00 = t00 * m0 + t10 * m1;
                    _m01 = t01 * m0 + t11 * m1;
                    _m02 += t02 * m0 + t12 * m1;

                    m0 = _m10;
                    m1 = _m11;
                    _m10 = t00 * m0 + t10 * m1;
                    _m11 = t01 * m0 + t11 * m1;
                    _m12 += t02 * m0 + t12 * m1;
                    _type = TYPE_UNKNOWN;
                    return;

                case (APPLY_SHEAR | APPLY_TRANSLATE):
                case (APPLY_SHEAR):
                    m0 = _m01;
                    _m00 = t10 * m0;
                    _m01 = t11 * m0;
                    _m02 += t12 * m0;

                    m0 = _m10;
                    _m10 = t00 * m0;
                    _m11 = t01 * m0;
                    _m12 += t02 * m0;
                    break;

                case (APPLY_SCALE | APPLY_TRANSLATE):
                case (APPLY_SCALE):
                    m0 = _m00;
                    _m00 = t00 * m0;
                    _m01 = t01 * m0;
                    _m02 += t02 * m0;

                    m0 = _m11;
                    _m10 = t10 * m0;
                    _m11 = t11 * m0;
                    _m12 += t12 * m0;
                    break;

                case (APPLY_TRANSLATE):
                    _m00 = t00;
                    _m01 = t01;
                    _m02 += t02;

                    _m10 = t10;
                    _m11 = t11;
                    _m12 += t12;
                    _state = txstate | APPLY_TRANSLATE;
                    _type = TYPE_UNKNOWN;
                    return;
            }
            UpdateState();
        }
        // Date       Name                 Tracking #         Description
        // ---------  -------------------  -------------      ----------------------
        // 15JUN2009  James Shen                 	          Initial Creation
        ////////////////////////////////////////////////////////////////////////////
        /**
         * Constructs a {@code RadialGradientBrush}.
         *
         * @param center the center point in user space of the circle defining the
         *               gradient.  The last color of the gradient is mapped to
         *               the perimeter of this circle.
         * @param radius the radius of the circle defining the extents of the
         *               color gradient
         * @param fractions numbers ranging from 0.0 to 1.0 specifying the
         *                  distribution of colors along the gradient
         * @param colors array of colors to use in the gradient.  The first color
         *               is used at the focus point, the last color around the
         *               perimeter of the circle.
         * @param fillType either {@code NO_CYCLE}, {@code REFLECT},
         *                    or {@code REPEAT}
         * @param gradientTransform transform to apply to the gradient
         *
         * @throws NullPointerException
         * if one of the points is null,
         * or {@code fractions} array is null,
         * or {@code colors} array is null,
         * or {@code cycleMethod} is null,
         * or {@code colorSpace} is null,
         * or {@code gradientTransform} is null
         * @throws IllegalArgumentException
         * if {@code radius} is non-positive,
         * or {@code fractions.length != colors.length},
         * or {@code colors} is less than 2 in size,
         * or a {@code fractions} Value is less than 0.0 or greater than 1.0,
         * or the {@code fractions} are not provided in strictly increasing order
         */
        public RadialGradientBrush(Point center,
                int radius,
                int[] fractions, Color[] colors,
                int fillType,
                AffineTransform gradientTransform)
        {
            if (fractions == null)
            {
                throw new NullReferenceException("Fractions array cannot be null");
            }

            if (colors == null)
            {
                throw new NullReferenceException("Colors array cannot be null");
            }

            if (gradientTransform == null)
            {
                throw new NullReferenceException("Gradient transform cannot be " +
                        "null");
            }

            if (fractions.Length != colors.Length)
            {
                throw new ArgumentException("Colors and fractions must " +
                        "have equal size");
            }

            if (colors.Length < 2)
            {
                throw new ArgumentException("User must specify at least " +
                        "2 colors");
            }

            // check that values are in the proper range and progress
            // in increasing order from 0 to 1
            int previousFraction = -255;
            for (int i = 0; i < fractions.Length; i++)
            {
                int currentFraction = fractions[i];
                if (currentFraction < 0 || currentFraction > 255)
                {
                    throw new ArgumentException("Fraction values must " +
                            "be in the range 0 to 255: " +
                            currentFraction);
                }

                if (currentFraction <= previousFraction)
                {
                    throw new ArgumentException("Keyframe fractions " +
                            "must be increasing: " +
                            currentFraction);
                }

                previousFraction = currentFraction;
            }

            // We have to deal with the cases where the first gradient stop is not
            // equal to 0 and/or the last gradient stop is not equal to 1.
            // In both cases, create a new point and replicate the previous
            // extreme point's color.
            bool fixFirst = false;
            bool fixLast = false;
            int len = fractions.Length;
            int off = 0;

            if (fractions[0] != 0)
            {
                // first stop is not equal to zero, fix this condition
                fixFirst = true;
                len++;
                off++;
            }
            if (fractions[fractions.Length - 1] != 255)
            {
                // last stop is not equal to one, fix this condition
                fixLast = true;
                len++;
            }

            _fractions = new int[len];
            Array.Copy(fractions, 0, _fractions, off, fractions.Length);
            _colors = new Color[len];
            Array.Copy(colors, 0, _colors, off, colors.Length);

            if (fixFirst)
            {
                _fractions[0] = 0;
                _colors[0] = colors[0];
            }
            if (fixLast)
            {
                _fractions[len - 1] = 255;
                _colors[len - 1] = colors[colors.Length - 1];
            }

            // copy the gradient transform
            _gradientTransform = new AffineTransform(gradientTransform);

            // determine transparency
            bool opaque = true;
            for (int i = 0; i < colors.Length; i++)
            {
                opaque = opaque && (colors[i].GetAlpha() == 0xff);
            }
            _transparency = opaque ? Color.OPAQUE : Color.TRANSLUCENT;

            // check input arguments
            if (center == null)
            {
                throw new NullReferenceException("Center point must be non-null");
            }

            if (radius <= 0)
            {
                throw new ArgumentException("Radius must be greater " +
                        "than zero");
            }

            // copy parameters
            _center = new Point(center.X, center.Y);
            _radius = radius;
            _fillType = fillType;

            _wrappedBrushFP = new RadialGradientBrushFP(SingleFP.FromInt(center.X),
                    SingleFP.FromInt(center.Y), SingleFP.FromInt(radius), 0);
            for (int i = 0; i < colors.Length; i++)
            {
                ((RadialGradientBrushFP)_wrappedBrushFP).SetGradientColor(SingleFP.FromFloat(fractions[i] / 100.0f),
                        colors[i]._value);
            }
            ((RadialGradientBrushFP)_wrappedBrushFP).UpdateGradientTable();
            _wrappedBrushFP.SetMatrix(Utils.ToMatrixFP(gradientTransform));
            _wrappedBrushFP.FillMode = fillType;
        }