Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/SharpVectorCore/Svg/SvgTransformF.cs @ 13847

Last change on this file since 13847 was 12762, checked in by aballeit, 9 years ago

#2283 GUI updates, Tree-chart, MCTS Version 2 (prune leaves)

File size: 32.3 KB
Line 
1using System;
2
3namespace SharpVectors.Dom.Svg
4{
5    /// <summary>
6    /// This is an implementation of the 3-by-3 affine matrix that represents
7    /// a geometric transform.
8    /// </summary>
9    public class SvgTransformF : ICloneable
10    {
11        #region Private Fields
12
13        private float m11;
14        private float m12;
15        private float m21;
16        private float m22;
17        private float dx;
18        private float dy;
19
20        #endregion
21
22        #region Constructors and Destructor
23
24        /// <overloads>
25        /// Initializes a new instance of the <see cref="SvgTransformF"/> class.
26        /// </overloads>
27        /// <summary>
28        /// Initializes a new instance of the <see cref="SvgTransformF"/> class
29        /// as the identity transform or matrix.
30        /// </summary>
31        public SvgTransformF()
32        {
33            m11 = 1.0f;
34            m12 = 0.0f;
35            m21 = 0.0f;
36            m22 = 1.0f;
37            dx  = 0.0f;
38            dy  = 0.0f;
39        }
40
41        /// <summary>
42        /// Initializes a new instance of the <see cref="SvgTransformF"/> class
43        /// to the geometric transform defined by the specified rectangle and
44        /// array of points.
45        /// </summary>
46        /// <param name="rect">
47        /// A <see cref="SvgRectF"/> structure that represents the rectangle
48        /// to be transformed.
49        /// </param>
50        /// <param name="plgpts">
51        /// An array of three <see cref="SvgPointF"/> structures that represents the
52        /// points of a parallelogram to which the upper-left, upper-right, and
53        /// lower-left corners of the rectangle is to be transformed. The
54        /// lower-right corner of the parallelogram is implied by the first three
55        /// corners.
56        /// </param>
57        /// <exception cref="ArgumentNullException">
58        /// If the <paramref name="plgpts"/> is <see langword="null"/>.
59        /// </exception>
60        /// <exception cref="ArgumentException">
61        /// If the length of the <paramref name="plgpts"/> array is not equal
62        /// to 3.
63        /// </exception>
64        /// <exception cref="ArgumentOutOfRangeException">
65        /// If the width or height of the <paramref name="rect"/> is zero.
66        /// </exception>
67        public SvgTransformF(SvgRectF rect, SvgPointF[] plgpts)
68        {
69            if (plgpts == null)
70            {
71                throw new ArgumentNullException("plgpts");
72            }
73            if (plgpts.Length != 3)
74            {
75                throw new ArgumentException("plgpts");
76            }
77
78            if ((rect.Width == 0) || (rect.Height == 0))
79            {
80                throw new ArgumentOutOfRangeException("rect");
81            }
82
83            MapRectToRect(rect, plgpts);
84        }
85
86        /// <summary>
87        /// Initializes a new instance of the <see cref="SvgTransformF"/> class
88        /// with the specified elements.
89        /// </summary>
90        /// <param name="elements">
91        /// An array of six items defining the transform.
92        /// </param>
93        /// <exception cref="ArgumentNullException">
94        /// If the <paramref name="elements"/> is <see langword="null"/>.
95        /// </exception>
96        /// <exception cref="ArgumentException">
97        /// If the length of the <paramref name="elements"/> array is not equal
98        /// to 6.
99        /// </exception>
100        public SvgTransformF(float[] elements)
101        {
102            if (elements == null)
103            {
104                throw new ArgumentNullException("elements");
105            }
106            if (elements.Length != 6)
107            {
108                throw new ArgumentException("elements");
109            }
110
111            this.m11 = elements[0];
112            this.m12 = elements[1];
113            this.m21 = elements[2];
114            this.m22 = elements[3];
115            this.dx  = elements[4];
116            this.dy  = elements[5];
117        }
118
119        /// <summary>
120        /// Initializes a new instance of the <see cref="SvgTransformF"/> class
121        /// with the specified elements.
122        /// </summary>
123        /// <param name="m11">
124        /// The value in the first row and first column of the new <see cref="SvgTransformF"/>.
125        /// </param>
126        /// <param name="m12">
127        /// The value in the first row and second column of the new <see cref="SvgTransformF"/>.
128        /// </param>
129        /// <param name="m21">
130        /// The value in the second row and first column of the new <see cref="SvgTransformF"/>.
131        /// </param>
132        /// <param name="m22">
133        /// The value in the second row and second column of the new <see cref="SvgTransformF"/>.
134        /// </param>
135        /// <param name="dx">
136        /// The value in the third row and first column of the new <see cref="SvgTransformF"/>.
137        /// </param>
138        /// <param name="dy">
139        /// The value in the third row and second column of the new <see cref="SvgTransformF"/>.
140        /// </param>
141        public SvgTransformF(float m11, float m12, float m21, float m22,
142                      float dx, float dy)
143        {
144            this.m11 = m11;
145            this.m12 = m12;
146            this.m21 = m21;
147            this.m22 = m22;
148            this.dx = dx;
149            this.dy = dy;
150        }
151
152        /// <summary>
153        /// Initializes a new instance of the <see cref="SvgTransformF"/> class
154        /// with parameters copied from the specified parameter, a copy
155        /// constructor.
156        /// </summary>
157        /// <param name="source">
158        /// The <see cref="SvgTransformF"/> instance from which the parameters
159        /// are to be copied.
160        /// </param>
161        /// <exception cref="ArgumentNullException">
162        /// If the <paramref name="source"/> is <see langword="null"/>.
163        /// </exception>
164        public SvgTransformF(SvgTransformF source)
165        {
166            if (source == null)
167            {
168                throw new ArgumentNullException("source");
169            }
170
171            this.m11 = source.m11;
172            this.m12 = source.m12;
173            this.m21 = source.m21;
174            this.m22 = source.m22;
175            this.dx  = source.dx;
176            this.dy  = source.dy;
177        }
178
179        #endregion
180
181        #region Public Properties
182
183        /// <summary>
184        /// Gets an array of floating-point values that represents the elements
185        /// of this <see cref="SvgTransformF"/>.
186        /// </summary>
187        /// <value>
188        /// An array of floating-point values that represents the elements
189        /// of this <see cref="SvgTransformF"/>.
190        /// </value>
191        public float[] Elements
192        {
193            get
194            {
195        return new float[] {m11, m12, m21, m22, dx, dy};
196            }
197        }
198
199        /// <summary>               
200        /// Gets a value indicating whether this <see cref="SvgTransformF"/> is the
201        /// identity matrix.
202        /// </summary>
203        /// <value>
204        /// This property is <see langword="true"/> if this
205        /// <see cref="SvgTransformF"/> is identity; otherwise, <see langword="false"/>.
206        /// </value>
207        public bool IsIdentity
208        {
209            get
210            {
211                return (m11 == 1.0f && m12 == 0.0f &&
212                        m21 == 0.0f && m22 == 1.0f &&
213                        dx == 0.0f && dy == 0.0f);
214            }
215        }
216
217        /// <summary>
218        /// Gets a value indicating whether this <see cref="SvgTransformF"/> is
219        /// invertible.
220        /// </summary>
221        /// <value>
222        /// This property is <see langword="true"/> if this
223        /// <see cref="SvgTransformF"/> is invertible; otherwise, <see langword="false"/>.
224        /// </value>
225        public bool IsInvertible
226        {
227            get
228            {
229                return ((m11 * m22 - m21 * m11) != 0.0f);
230            }
231        }
232
233        /// <summary>
234        /// Gets the <c>x</c> translation value (the <c>dx</c> value, or the
235        /// element in the third row and first column) of this <see cref="SvgTransformF"/>.
236        /// </summary>
237        /// <value>
238        /// The <c>x</c> translation value of this <see cref="SvgTransformF"/>.
239        /// </value>
240        public float OffsetX
241        {
242            get
243            {
244                return dx;
245            }
246        }
247
248        /// <summary>
249        /// Gets the <c>y</c> translation value (the <c>dy</c> value, or the
250        /// element in the third row and second column) of this <see cref="SvgTransformF"/>.
251        /// </summary>
252        /// <value>
253        /// The <c>y</c> translation value of this <see cref="SvgTransformF"/>.
254        /// </value>
255        public float OffsetY
256        {
257            get
258            {
259                return dy;
260            }
261        }
262
263        #endregion
264
265        #region Public Methods
266
267        /// <summary>
268        /// Determine whether the specified object is a <see cref="SvgTransformF"/>
269        /// and is identical to this <see cref="SvgTransformF"/>.
270        /// </summary>
271        /// <param name="obj">The object to test.</param>
272        /// <returns>
273        /// This method returns <see langword="true"/> if obj is the specified
274        /// <see cref="SvgTransformF"/> identical to this
275        /// <see cref="SvgTransformF"/>; otherwise, <see langword="false"/>.
276        /// </returns>
277        public override bool Equals(Object obj)
278        {
279            SvgTransformF other = (obj as SvgTransformF);
280            if (other != null)
281            {
282                return (other.m11 == m11 && other.m12 == m12 &&
283                        other.m21 == m21 && other.m22 == m22 &&
284                        other.dx  == dx  && other.dy  == dy);
285            }
286
287            return false;
288        }
289
290        /// <summary>
291        /// Returns a hash code.
292        /// </summary>
293        /// <returns>The hash code for this <see cref="SvgTransformF"/>.</returns>
294        public override int GetHashCode()
295        {
296            return (int)(m11 + m12 + m21 + m22 + dx + dy);
297        }
298
299        /// <summary>
300        /// Inverts this <see cref="SvgTransformF"/>, if it is invertible.
301        /// </summary>
302        public void Invert()
303        {
304            float determinant = this.m11 * this.m22 - this.m21 * this.m11;
305            if (determinant != 0.0f)
306            {
307                float nm11 = this.m22 / determinant;
308                float nm12 = -(this.m12 / determinant);
309                float nm21 = -(this.m21 / determinant);
310                float nm22 = this.m11 / determinant;
311                float ndx  = (this.m12 * this.dy - this.m22 * this.dx) / determinant;
312                float ndy  = (this.m21 * this.dx - this.m11 * this.dy) / determinant;
313
314                this.m11 = nm11;
315                this.m12 = nm12;
316                this.m21 = nm21;
317                this.m22 = nm22;
318                this.dx  = ndx;
319                this.dy  = ndy;
320            }
321        }
322
323        /// <overloads>
324        /// Multiplies this <see cref="SvgTransformF"/> by the specified
325        /// <see cref="SvgTransformF"/> by appending or prepending the specified
326        /// <see cref="SvgTransformF"/>.
327        /// </overloads>
328        /// <summary>
329        /// Multiplies this <see cref="SvgTransformF"/> by the specified
330        /// <see cref="SvgTransformF"/> by prepending the specified
331        /// <see cref="SvgTransformF"/>.
332        /// </summary>
333        /// <param name="matrix">
334        /// The <see cref="SvgTransformF"/> by which this <see cref="SvgTransformF"/>
335        /// is to be multiplied.
336        /// </param>
337        public void Multiply(SvgTransformF matrix)
338        {
339            if (matrix == null)
340            {
341                throw new ArgumentNullException("matrix");
342            }
343            Multiply((SvgTransformF)matrix, this);
344        }
345
346        /// <summary>
347        /// Multiplies this <see cref="SvgTransformF"/> by the matrix specified in
348        /// the matrix parameter, and in the order specified in the order parameter.
349        /// </summary>
350        /// <param name="matrix">
351        /// The <see cref="SvgTransformF"/> by which this <see cref="SvgTransformF"/>
352        /// is to be multiplied.
353        /// </param>
354        /// <param name="order">
355        /// The <see cref="TransformOrder"/> that represents the order of the
356        /// multiplication.
357        /// </param>
358        public void Multiply(SvgTransformF matrix, SvgTransformOrder order)
359        {
360            if (matrix == null)
361            {
362                throw new ArgumentNullException("matrix");
363            }
364            if (order == SvgTransformOrder.Prepend)
365            {
366                Multiply((SvgTransformF)matrix, this);
367            }
368            else
369            {
370                Multiply(this, (SvgTransformF)matrix);
371            }
372        }
373
374        /// <summary>
375        /// Multiplies this <see cref="SvgTransformF"/> by the specified
376        /// <see cref="SvgTransformF"/> by prepending the specified
377        /// <see cref="SvgTransformF"/>.
378        /// </summary>
379        /// <param name="matrix">
380        /// The <see cref="SvgTransformF"/> by which this <see cref="SvgTransformF"/>
381        /// is to be multiplied.
382        /// </param>
383        //public void Multiply(SvgTransformF matrix)
384        //{
385        //    if (matrix == null)
386        //    {
387        //        throw new ArgumentNullException("matrix");
388        //    }
389        //    Multiply(matrix, this);
390        //}
391
392        /// <summary>
393        /// Multiplies this <see cref="SvgTransformF"/> by the matrix specified in
394        /// the matrix parameter, and in the order specified in the order parameter.
395        /// </summary>
396        /// <param name="matrix">
397        /// The <see cref="SvgTransformF"/> by which this <see cref="SvgTransformF"/>
398        /// is to be multiplied.
399        /// </param>
400        /// <param name="order">
401        /// The <see cref="TransformOrder"/> that represents the order of the
402        /// multiplication.
403        /// </param>
404        //public void Multiply(SvgTransformF matrix, TransformOrder order)
405        //{
406        //    if (matrix == null)
407        //    {
408        //        throw new ArgumentNullException("matrix");
409        //    }
410        //    if (order == TransformOrder.Prepend)
411        //    {
412        //        Multiply(matrix, this);
413        //    }
414        //    else
415        //    {
416        //        Multiply(this, matrix);
417        //    }
418        //}
419
420        /// <summary>
421        /// Resets this <see cref="SvgTransformF"/> to have the elements of the
422        /// identity matrix.
423        /// </summary>
424        public void Reset()
425        {
426            m11 = 1.0f;
427            m12 = 0.0f;
428            m21 = 0.0f;
429            m22 = 0.1f;
430            dx  = 0.0f;
431            dy  = 0.0f;
432        }
433
434        /// <overloads>
435        /// Applies a clockwise rotation of the specified angle about the
436        /// origin to this <see cref="SvgTransformF"/>.
437        /// </overloads>
438        /// <summary>
439        /// Applies a clockwise rotation of the specified angle about the
440        /// origin to this <see cref="SvgTransformF"/>.
441        /// </summary>
442        /// <param name="angle">
443        /// The angle (extent) of the rotation, in degrees.
444        /// </param>
445        public void Rotate(float angle)
446        {
447      double radians = (angle * (Math.PI / 180.0));
448      float cos = (float)(Math.Cos(radians));
449      float sin = (float)(Math.Sin(radians));
450
451      float nm11 = cos * this.m11 + sin * this.m21;
452      float nm12 = cos * this.m12 + sin * this.m22;
453      float nm21 = cos * this.m21 - sin * this.m11;
454      float nm22 = cos * this.m22 - sin * this.m12;
455
456      this.m11 = nm11;
457      this.m12 = nm12;
458      this.m21 = nm21;
459      this.m22 = nm22;
460        }
461
462        /// <summary>
463        /// Applies a clockwise rotation of the specified angle about the
464        /// origin to this <see cref="SvgTransformF"/>, and in the order specified
465        /// in the order parameter.
466        /// </summary>
467        /// <param name="angle">
468        /// The angle (extent) of the rotation, in degrees.
469        /// </param>
470        /// <param name="order">
471        /// A <see cref="TransformOrder"/> that specifies the order (append or
472        /// prepend) in which the rotation is applied to this
473        /// <see cref="SvgTransformF"/>.
474        /// </param>
475        public void Rotate(float angle, SvgTransformOrder order)
476        {
477      double radians = (angle * (Math.PI / 180.0));
478      float cos = (float)(Math.Cos(radians));
479      float sin = (float)(Math.Sin(radians));
480
481      if (order == SvgTransformOrder.Prepend)
482      {
483        float nm11 = cos * this.m11 + sin * this.m21;
484        float nm12 = cos * this.m12 + sin * this.m22;
485        float nm21 = cos * this.m21 - sin * this.m11;
486        float nm22 = cos * this.m22 - sin * this.m12;
487
488        this.m11 = nm11;
489        this.m12 = nm12;
490        this.m21 = nm21;
491        this.m22 = nm22;
492      }
493      else
494      {
495        float nm11 = this.m11 * cos - this.m12 * sin;
496        float nm12 = this.m11 * sin + this.m12 * cos;
497        float nm21 = this.m21 * cos - this.m22 * sin;
498        float nm22 = this.m21 * sin + this.m22 * cos;
499        float ndx  = this.dx  * cos - this.dy  * sin;
500        float ndy  = this.dx  * sin + this.dy  * cos;
501
502        this.m11 = nm11;
503        this.m12 = nm12;
504        this.m21 = nm21;
505        this.m22 = nm22;
506        this.dx  = ndx;
507        this.dy  = ndy;
508      }
509        }
510
511        /// <overloads>
512        /// Applies a clockwise rotation about the specified point to this
513        /// <see cref="SvgTransformF"/> by appending or prepending the rotation.
514        /// </overloads>
515        /// <summary>
516        /// Applies a clockwise rotation about the specified point to this
517        /// <see cref="SvgTransformF"/> by prepending the rotation.
518        /// </summary>
519        /// <param name="angle">
520        /// The angle (extent) of the rotation, in degrees.
521        /// </param>
522        /// <param name="point">
523        /// A <see cref="SvgPointF"/> that represents the center of the rotation.
524        /// </param>
525        public void RotateAt(float angle, SvgPointF point)
526        {
527            Translate(point.X, point.Y);
528            Rotate(angle);
529            Translate(-point.X, -point.Y);
530        }
531
532        /// <summary>
533        /// Applies a clockwise rotation about the specified point to this
534        /// <see cref="SvgTransformF"/> in the specified order.
535        /// </summary>
536        /// <param name="angle">
537        /// The angle (extent) of the rotation, in degrees.
538        /// </param>
539        /// <param name="point">
540        /// A <see cref="SvgPointF"/> that represents the center of the rotation.
541        /// </param>
542        /// <param name="order">
543        /// A <see cref="TransformOrder"/> that specifies the order (append or
544        /// prepend) in which the rotation is applied.
545        /// </param>
546        public void RotateAt(float angle, SvgPointF point, SvgTransformOrder order)
547        {
548            if (order == SvgTransformOrder.Prepend)
549            {
550                Translate(point.X, point.Y);
551                Rotate(angle);
552                Translate(-point.X, -point.Y);
553            }
554            else
555            {
556                Translate(-point.X, -point.Y);
557                Rotate(angle, SvgTransformOrder.Append);
558                Translate(point.X, point.Y);
559            }
560        }
561
562        /// <overloads>
563        /// Applies the specified scale vector to this <see cref="SvgTransformF"/>
564        /// by appending or prepending the scale vector.
565        /// </overloads>
566        /// <summary>
567        /// Applies the specified scale vector to this <see cref="SvgTransformF"/>
568        /// by prepending the scale vector.
569        /// </summary>
570        /// <param name="scaleX">
571        /// The value by which to scale this <see cref="SvgTransformF"/> in the
572        /// x-axis direction.
573        /// </param>
574        /// <param name="scaleY">
575        /// The value by which to scale this <see cref="SvgTransformF"/> in the
576        /// y-axis direction.
577        /// </param>
578        public void Scale(float scaleX, float scaleY)
579        {
580            m11 *= scaleX;
581            m12 *= scaleX;
582            m21 *= scaleY;
583            m22 *= scaleY;
584        }
585
586        /// <summary>
587        /// Applies the specified scale vector to this <see cref="SvgTransformF"/>
588        /// using the specified order.
589        /// </summary>
590        /// <param name="scaleX">
591        /// The value by which to scale this <see cref="SvgTransformF"/> in the
592        /// x-axis direction.
593        /// </param>
594        /// <param name="scaleY">
595        /// The value by which to scale this <see cref="SvgTransformF"/> in the
596        /// y-axis direction.
597        /// </param>
598        /// <param name="order">
599        /// A <see cref="TransformOrder"/> that specifies the order (append or
600        /// prepend) in which the scale vector is applied to this
601        /// <see cref="SvgTransformF"/>.
602        /// </param>
603        public void Scale(float scaleX, float scaleY, SvgTransformOrder order)
604        {
605            if (order == SvgTransformOrder.Prepend)
606            {
607                m11 *= scaleX;
608                m12 *= scaleX;
609                m21 *= scaleY;
610                m22 *= scaleY;
611            }
612            else
613            {
614                m11 *= scaleX;
615                m12 *= scaleY;
616                m21 *= scaleX;
617                m22 *= scaleY;
618                dx *= scaleX;
619                dy *= scaleY;
620            }
621        }
622
623        /// <overloads>
624        /// Applies the specified shear vector to this <see cref="SvgTransformF"/> by
625        /// appending or prepending the shear vector.
626        /// </overloads>
627        /// <summary>
628        /// Applies the specified shear vector to this <see cref="SvgTransformF"/> by
629        /// prepending the shear vector.
630        /// </summary>
631        /// <param name="shearX">
632        /// The horizontal shear factor.
633        /// </param>
634        /// <param name="shearY">
635        /// The vertical shear factor.
636        /// </param>
637        public void Shear(float shearX, float shearY)
638        {
639            float nm11 = this.m11 + this.m21 * shearY;
640            float nm12 = this.m12 + this.m22 * shearY;
641            float nm21 = this.m11 * shearX + this.m21;
642            float nm22 = this.m12 * shearX + this.m22;
643
644            this.m11 = nm11;
645            this.m12 = nm12;
646            this.m21 = nm21;
647            this.m22 = nm22;
648        }
649
650        /// <summary>
651        /// Applies the specified shear vector to this <see cref="SvgTransformF"/> in
652        /// the specified order.
653        /// </summary>
654        /// <param name="shearX">
655        /// The horizontal shear factor.
656        /// </param>
657        /// <param name="shearY">
658        /// The vertical shear factor.
659        /// </param>
660        /// <param name="order">
661        /// A <see cref="TransformOrder"/> that specifies the order (append or
662        /// prepend) in which the shear is applied.
663        /// </param>
664        public void Shear(float shearX, float shearY, SvgTransformOrder order)
665        {
666            if (order == SvgTransformOrder.Prepend)
667            {
668                float nm11 = this.m11 + this.m21 * shearY;
669                float nm12 = this.m12 + this.m22 * shearY;
670                float nm21 = this.m11 * shearX + this.m21;
671                float nm22 = this.m12 * shearX + this.m22;
672
673                this.m11 = nm11;
674                this.m12 = nm12;
675                this.m21 = nm21;
676                this.m22 = nm22;
677            }
678            else
679            {
680                float nm11 = this.m11 + this.m12 * shearX;
681                float nm12 = this.m11 * shearY + this.m12;
682                float nm21 = this.m21 + this.m22 * shearX;
683                float nm22 = this.m21 * shearY + this.m22;
684                float ndx = this.dx + this.dy * shearX;
685                float ndy = this.dx * shearY + this.dy;
686
687                this.m11 = nm11;
688                this.m12 = nm12;
689                this.m21 = nm21;
690                this.m22 = nm22;
691                this.dx  = ndx;
692                this.dy  = ndy;
693            }
694        }
695
696        /// <overloads>
697        /// Applies the specified translation vector to this <see cref="SvgTransformF"/>
698        /// by appending or prepending the translation vector.
699        /// </overloads>
700        /// <summary>
701        /// Applies the specified translation vector to this <see cref="SvgTransformF"/>
702        /// by prepending the translation vector.
703        /// </summary>
704        /// <param name="offsetX">
705        /// The <c>x</c> value by which to translate this <see cref="SvgTransformF"/>.
706        /// </param>
707        /// <param name="offsetY">
708        /// The <c>y</c> value by which to translate this <see cref="SvgTransformF"/>.
709        /// </param>
710        public void Translate(float offsetX, float offsetY)
711        {
712            dx += offsetX * m11 + offsetY * m21;
713            dy += offsetX * m12 + offsetY * m22;
714        }
715
716        /// <summary>
717        /// Applies the specified translation vector to this <see cref="SvgTransformF"/>
718        /// in the specified order.
719        /// </summary>
720        /// <param name="offsetX">
721        /// The <c>x</c> value by which to translate this <see cref="SvgTransformF"/>.
722        /// </param>
723        /// <param name="offsetY">
724        /// The <c>y</c> value by which to translate this <see cref="SvgTransformF"/>.
725        /// </param>
726        /// <param name="order">
727        /// A <see cref="TransformOrder"/> that specifies the order (append or
728        /// prepend) in which the translation is applied to this <see cref="SvgTransformF"/>.
729        /// </param>
730        public void Translate(float offsetX, float offsetY, SvgTransformOrder order)
731        {
732            if (order == SvgTransformOrder.Prepend)
733            {
734                dx += offsetX * m11 + offsetY * m21;
735                dy += offsetX * m12 + offsetY * m22;
736            }
737            else
738            {
739                dx += offsetX;
740                dy += offsetY;
741            }
742        }
743
744        /// <summary>
745        /// Applies the geometric transform represented by this
746        /// <see cref="SvgTransformF"/> to a specified point.
747        /// </summary>
748        /// <param name="x">The input <c>x</c> value of the point.</param>
749        /// <param name="y">The input <c>y</c> value of the point.</param>
750        /// <param name="ox">The transformed <c>x</c> value of the point.</param>
751        /// <param name="oy">The transformed <c>y</c> value of the point.</param>
752        public void Transform(float x, float y, out float ox, out float oy)
753        {
754            ox = x * m11 + y * m21 + dx;
755            oy = x * m12 + y * m22 + dy;
756        }
757
758        /// <summary>
759        /// Applies the reverse geometric transform represented by this
760        /// <see cref="SvgTransformF"/> to a specified point.
761        /// </summary>
762        /// <param name="x">The input <c>x</c> value of the point.</param>
763        /// <param name="y">The input <c>y</c> value of the point.</param>
764        /// <param name="ox">The transformed <c>x</c> value of the point.</param>
765        /// <param name="oy">The transformed <c>y</c> value of the point.</param>
766        public void ReverseTransform(float x, float y, out float ox, out float oy)
767        {
768            float determinant = this.m11 * this.m22 - this.m21 * this.m11;
769            if (determinant != 0.0f)
770            {
771                float nm11 =   this.m22 / determinant;
772                float nm12 = -(this.m12 / determinant);
773                float nm21 = -(this.m21 / determinant);
774                float nm22 =   this.m11 / determinant;
775
776                ox = x * nm11 + y * nm21;
777                oy = x * nm12 + y * nm22;
778            }
779            else
780            {
781                ox = x;
782                oy = y;
783            }
784        }
785
786        /// <summary>
787        /// Applies the geometric transform represented by this
788        /// <see cref="SvgTransformF"/> to a specified array of points.
789        /// </summary>
790        /// <param name="pts">
791        /// An array of <see cref="SvgPointF"/> structures that represents the points
792        /// to transform.
793        /// </param>
794        public void TransformPoints(SvgPointF[] pts)
795        {
796            if (pts == null)
797            {
798                throw new ArgumentNullException("pts");
799            }
800
801            int nLength = pts.Length;
802
803            for (int i = nLength - 1; i >= 0; --i)
804            {
805                float x  = pts[i].X;
806                float y  = pts[i].Y;
807                pts[i].ValueX = x * m11 + y * m21 + dx;
808                pts[i].ValueY = x * m12 + y * m22 + dy;
809            }
810        }
811
812        /// <summary>
813        /// Multiplies each vector in an array by the matrix. The translation
814        /// elements of this matrix (third row) are ignored.
815        /// </summary>
816        /// <param name="pts">
817        /// An array of <see cref="SvgPointF"/> structures that represents the points
818        /// to transform.
819        /// </param>
820        public void TransformVectors(SvgPointF[] pts)
821        {
822            if (pts == null)
823            {
824                throw new ArgumentNullException("pts");
825            }
826
827            int nLength = pts.Length;
828
829            for (int i = nLength - 1; i >= 0; --i)
830            {
831                float x  = pts[i].X;
832                float y  = pts[i].Y;
833                pts[i].ValueX = x * m11 + y * m21;
834                pts[i].ValueY = x * m12 + y * m22;
835            }
836        }
837
838        #endregion
839
840        #region Private Methods
841
842        private void Multiply(SvgTransformF a, SvgTransformF b)
843        {
844            float nm11 = a.m11 * b.m11 + a.m12 * b.m21;
845            float nm12 = a.m11 * b.m12 + a.m12 * b.m22;
846            float nm21 = a.m21 * b.m11 + a.m22 * b.m21;
847            float nm22 = a.m21 * b.m12 + a.m22 * b.m22;
848            float ndx  = a.dx  * b.m11 + a.dy  * b.m21 + b.dx;
849            float ndy  = a.dx  * b.m12 + a.dy  * b.m22 + b.dy;
850
851            this.m11 = nm11;
852            this.m12 = nm12;
853            this.m21 = nm21;
854            this.m22 = nm22;
855            this.dx  = ndx;
856            this.dy  = ndy;
857        }
858
859        private void MapRectToRect(SvgRectF rect, SvgPointF[] plgpts)
860        {
861            SvgPointF pt1 = new SvgPointF(plgpts[1].X - plgpts[0].X,
862                            plgpts[1].Y - plgpts[0].Y);
863            SvgPointF pt2 = new SvgPointF(plgpts[2].X - plgpts[0].X,
864                            plgpts[2].Y - plgpts[0].Y);
865
866            this.m11 = pt1.X / rect.Width;
867            this.m12 = pt1.Y / rect.Width;
868            this.m21 = pt2.X / rect.Height;
869            this.m22 = pt2.Y / rect.Height;
870            this.dx = plgpts[0].X - rect.X / rect.Width * pt1.X - rect.Y / rect.Height * pt2.X;
871            this.dy = plgpts[0].Y - rect.X / rect.Width * pt1.Y - rect.Y / rect.Height * pt2.Y;
872        }
873
874        #endregion
875
876        #region ICloneable Members
877
878        /// <summary>
879        /// This creates a new <see cref="SvgTransformF"/> that is a deep
880        /// copy of the current instance.
881        /// </summary>
882        /// <returns>A new object that is a copy of this instance.</returns>
883        public SvgTransformF Clone()
884        {
885            return new SvgTransformF(this.m11, this.m12,
886                              this.m21, this.m22,
887                              this.dx, this.dy);
888        }
889
890        /// <summary>
891        /// This creates a new <see cref="SvgTransformF"/> that is a deep
892        /// copy of the current instance.
893        /// </summary>
894        /// <returns>A new object that is a copy of this instance.</returns>
895        //ITransform ITransform.Clone()
896        //{
897        //    return this.Clone();
898        //}
899
900        /// <summary>
901        /// This creates a new <see cref="SvgTransformF"/> that is a deep
902        /// copy of the current instance.
903        /// </summary>
904        /// <returns>A new object that is a copy of this instance.</returns>
905        object ICloneable.Clone()
906        {
907            return this.Clone();
908        }
909
910        #endregion
911    }
912}
Note: See TracBrowser for help on using the repository browser.