Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Problems.GrammaticalOptimization/SharpVectorRenderingGdi/Gdi/GdiGradientFill.cs @ 13777

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

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

File size: 15.0 KB
Line 
1using System;
2using System.Xml;
3using System.Drawing;
4using System.Drawing.Drawing2D;
5using System.Diagnostics;
6using System.Collections.Generic;
7using System.Runtime.InteropServices;
8
9using SharpVectors.Dom.Svg;
10using SharpVectors.Dom.Css;
11
12namespace SharpVectors.Renderers.Gdi
13{
14    /// <summary>
15    /// Summary description for PaintServer.
16    /// </summary>
17    public sealed class GdiGradientFill : GdiFill
18    {
19        #region Private Fields
20
21        private SvgGradientElement _gradientElement;
22
23        #endregion
24
25        #region Constructors and Destructor
26
27        public GdiGradientFill(SvgGradientElement gradientElement)
28        {
29            _gradientElement = gradientElement;
30        }
31
32        #endregion
33
34        #region Public Methods
35
36        public override Brush GetBrush(RectangleF bounds)
37        {
38            SvgLinearGradientElement linearGradient = _gradientElement as SvgLinearGradientElement;
39            if (linearGradient != null)
40            {
41                return GetLinearGradientBrush(linearGradient, bounds);
42            }
43
44            SvgRadialGradientElement radialGradient = _gradientElement as SvgRadialGradientElement;
45            if (radialGradient != null)
46            {
47                return GetRadialGradientBrush(radialGradient, bounds);
48            }
49
50            return new SolidBrush(Color.Black);
51        }
52
53        public Region GetRadialGradientRegion(RectangleF bounds)
54        {
55            SvgRadialGradientElement res = _gradientElement as SvgRadialGradientElement;
56
57            if (_gradientElement == null)
58            {
59                return null;
60            }
61
62            float fCenterX = (float)res.Cx.AnimVal.Value;
63            float fCenterY = (float)res.Cy.AnimVal.Value;
64            float fFocusX = (float)res.Fx.AnimVal.Value;
65            float fFocusY = (float)res.Fy.AnimVal.Value;
66            float fRadius = (float)res.R.AnimVal.Value;
67
68            float fEffectiveCX = fCenterX;
69            float fEffectiveCY = fCenterY;
70            float fEffectiveFX = fFocusX;
71            float fEffectiveFY = fFocusY;
72            float fEffectiveRadiusX = fRadius;
73            float fEffectiveRadiusY = fRadius;
74
75            if (res.GradientUnits.AnimVal.Equals(SvgUnitType.ObjectBoundingBox))
76            {
77                fEffectiveCX = bounds.Left + fCenterX * (bounds.Width);
78                fEffectiveCY = bounds.Top + fCenterY * (bounds.Height);
79                fEffectiveFX = bounds.Left + fFocusX * (bounds.Width);
80                fEffectiveFY = bounds.Top + fFocusY * (bounds.Height);
81                fEffectiveRadiusX = fRadius * bounds.Width;
82                fEffectiveRadiusY = fRadius * bounds.Height;
83            }
84
85            GraphicsPath gp2 = new GraphicsPath();
86            gp2.AddEllipse(fEffectiveCX - fEffectiveRadiusX, fEffectiveCY - fEffectiveRadiusY, 2 * fEffectiveRadiusX, 2 * fEffectiveRadiusY);
87
88            return new Region(gp2);
89        }
90
91        #endregion
92
93        #region Private Methods
94
95        private List<Color> GetColors(XmlNodeList stops)
96        {
97            List<Color> colors = new List<Color>(stops.Count);
98            for (int i = 0; i < stops.Count; i++)
99            {
100                SvgStopElement stop = (SvgStopElement)stops.Item(i);
101                string prop = stop.GetPropertyValue("stop-color");
102                GdiSvgColor svgColor = new GdiSvgColor(stop, "stop-color");
103
104                colors.Add(svgColor.Color);
105            }
106
107            return colors;
108        }
109
110        private List<float> GetPositions(XmlNodeList stops)
111        {
112            List<float> positions = new List<float>(stops.Count);
113            float lastPos = 0;
114            for (int i = 0; i < stops.Count; i++)
115            {
116                SvgStopElement stop = (SvgStopElement)stops.Item(i);
117                float pos = (float)stop.Offset.AnimVal;
118
119                pos /= 100;
120                pos = Math.Max(lastPos, pos);
121
122                positions.Add(pos);
123                lastPos = pos;
124            }
125
126            return positions;
127        }
128
129        private void GetCorrectPositions(List<float> positions, List<Color> colors)
130        {
131            if (positions.Count > 0)
132            {
133                float firstPos = positions[0];
134                if (firstPos > 0F)
135                {
136                    positions.Insert(0, 0F);
137                    colors.Insert(0, colors[0]);
138                }
139                float lastPos = positions[positions.Count - 1];
140                if (lastPos < 1F)
141                {
142                    positions.Add(1F);
143                    colors.Add(colors[colors.Count - 1]);
144                }
145            }
146        }
147
148        private void GetColorsAndPositions(XmlNodeList stops, List<float> positions, List<Color> colors)
149        {
150            List<Color> alColors    = GetColors(stops);
151            List<float> alPositions = GetPositions(stops);
152
153            if (alPositions.Count > 0)
154            {
155                GetCorrectPositions(alPositions, alColors);
156
157                colors.AddRange(alColors);
158                positions.AddRange(alPositions);
159                //colors = alColors.ToArray();
160                //positions = alPositions.ToArray();
161            }
162            else
163            {
164                //colors = new Color[2];
165                //colors[0] = Color.Black;
166                //colors[1] = Color.Black;
167
168                colors.Add(Color.Black);
169                colors.Add(Color.Black);
170
171                //positions = new float[2];
172                //positions[0] = 0;
173                //positions[1] = 1;
174
175                positions.Add(0);
176                positions.Add(1);
177            }
178        }
179
180        private LinearGradientBrush GetLinearGradientBrush(SvgLinearGradientElement res, RectangleF bounds)
181        {
182            float fLeft   = (float)res.X1.AnimVal.Value;
183            float fRight  = (float)res.X2.AnimVal.Value;
184            float fTop    = (float)res.Y1.AnimVal.Value;
185            float fBottom = (float)res.Y2.AnimVal.Value;
186
187            bool bForceUserSpaceOnUse = (fLeft > 1 || fRight > 1 || fTop > 1 || fBottom > 1);
188
189            float fEffectiveLeft   = fLeft;
190            float fEffectiveRight  = fRight;
191            float fEffectiveTop    = fTop;
192            float fEffectiveBottom = fBottom;
193
194            if (res.GradientUnits.AnimVal.Equals((ushort)SvgUnitType.ObjectBoundingBox) && !bForceUserSpaceOnUse)
195            {
196                if (res.SpreadMethod.AnimVal.Equals((ushort)SvgSpreadMethod.Pad))
197                {
198                    fEffectiveRight = bounds.Right;
199                    fEffectiveLeft = bounds.Left;
200                }
201                else
202                {
203                    fEffectiveLeft = bounds.Left + fLeft * (bounds.Width);
204                    fEffectiveRight = bounds.Left + fRight * (bounds.Width);
205                }
206
207                fEffectiveTop    = bounds.Top + fTop * (bounds.Height);
208                fEffectiveBottom = bounds.Top + fBottom * (bounds.Height);
209            }
210
211            LinearGradientMode mode = LinearGradientMode.Horizontal;
212
213            if (fTop == fBottom)
214            {
215                mode = LinearGradientMode.Horizontal;
216            }
217            else
218            {
219                if (fLeft == fRight)
220                {
221                    mode = LinearGradientMode.Vertical;
222                }
223                else
224                {
225                    if (fLeft < fRight)
226                        mode = LinearGradientMode.ForwardDiagonal;
227                    else
228                        mode = LinearGradientMode.BackwardDiagonal;
229                }
230            }
231
232            float fEffectiveWidth = fEffectiveRight - fEffectiveLeft;
233
234            if (fEffectiveWidth <= 0)
235                fEffectiveWidth = bounds.Width;
236
237            float fEffectiveHeight = fEffectiveBottom - fEffectiveTop;
238
239            if (fEffectiveHeight <= 0)
240                fEffectiveHeight = bounds.Height;
241
242            LinearGradientBrush brush = new LinearGradientBrush(new RectangleF(fEffectiveLeft - 1,
243                fEffectiveTop - 1, fEffectiveWidth + 2, fEffectiveHeight + 2),
244                Color.White, Color.White, mode);
245
246            XmlNodeList stops = res.Stops;
247
248            ColorBlend cb = new ColorBlend();
249
250            List<Color> adjcolors    = new List<Color>();
251            List<float> adjpositions = new List<float>();
252            GetColorsAndPositions(stops, adjpositions, adjcolors);
253
254            if (res.GradientUnits.AnimVal.Equals((ushort)SvgUnitType.ObjectBoundingBox) && !bForceUserSpaceOnUse)
255            {
256                if (res.SpreadMethod.AnimVal.Equals((ushort)SvgSpreadMethod.Pad))
257                {
258                    for (int i = 0; i < adjpositions.Count; i++)
259                    {
260                        if (fLeft == fRight)
261                            adjpositions[i] = fTop + adjpositions[i] * (fBottom - fTop);
262                        else
263                            adjpositions[i] = fLeft + adjpositions[i] * (fRight - fLeft);
264                    }
265
266                    // this code corrects the values again... fix
267                    int nSize = adjcolors.Count;
268
269                    if (adjpositions[0] > 0.0)
270                        ++nSize;
271
272                    if (adjpositions[adjcolors.Count - 1] < 1)
273                        ++nSize;
274
275                    Color[] readjcolors    = new Color[nSize];
276                    float[] readjpositions = new float[nSize];
277
278                    if (adjpositions[0] > 0.0)
279                    {
280                        adjpositions.CopyTo(readjpositions, 1);
281                        adjcolors.CopyTo(readjcolors, 1);
282
283                        readjcolors[0]    = readjcolors[1];
284                        readjpositions[0] = 0;
285                    }
286                    else
287                    {
288                        adjpositions.CopyTo(readjpositions, 0);
289                        adjcolors.CopyTo(readjcolors, 0);
290                    }
291
292                    if (adjpositions[adjcolors.Count - 1] < 1)
293                    {
294                        readjcolors[nSize - 1]    = readjcolors[nSize - 2];
295                        readjpositions[nSize - 1] = 1;
296                    }
297
298                    cb.Colors    = readjcolors;
299                    cb.Positions = readjpositions;
300                }
301                else
302                {
303                    cb.Colors    = adjcolors.ToArray();
304                    cb.Positions = adjpositions.ToArray();
305                }
306            }
307            else
308            {
309                cb.Colors    = adjcolors.ToArray();
310                cb.Positions = adjpositions.ToArray();
311            }
312
313            brush.InterpolationColors = cb;
314
315            if (res.SpreadMethod.AnimVal.Equals((ushort)SvgSpreadMethod.Reflect))
316            {
317                brush.WrapMode = WrapMode.TileFlipXY;
318            }
319            else if (res.SpreadMethod.AnimVal.Equals((ushort)SvgSpreadMethod.Repeat))
320            {
321                brush.WrapMode = WrapMode.Tile;
322            }
323            else if (res.SpreadMethod.AnimVal.Equals((ushort)SvgSpreadMethod.Pad))
324            {
325                brush.WrapMode = WrapMode.Tile;
326            }
327
328            brush.Transform = GetTransformMatrix(res);
329
330            if (res.GetPropertyValue("color-interpolation") == "linearRGB")
331            {
332                brush.GammaCorrection = true;
333            }
334            else
335            {
336                brush.GammaCorrection = false;
337            }
338
339            return brush;
340        }
341
342        private Matrix GetTransformMatrix(SvgGradientElement gradientElement)
343        {
344            SvgMatrix svgMatrix = ((SvgTransformList)gradientElement.GradientTransform.AnimVal).TotalMatrix;
345
346            Matrix transformMatrix = new Matrix((float)svgMatrix.A, (float)svgMatrix.B, (float)svgMatrix.C,
347                (float)svgMatrix.D, (float)svgMatrix.E, (float)svgMatrix.F);
348
349            return transformMatrix;
350        }
351
352        private PathGradientBrush GetRadialGradientBrush(SvgRadialGradientElement res, RectangleF bounds)
353        {
354            float fCenterX = (float)res.Cx.AnimVal.Value;
355            float fCenterY = (float)res.Cy.AnimVal.Value;
356            float fFocusX  = (float)res.Fx.AnimVal.Value;
357            float fFocusY  = (float)res.Fy.AnimVal.Value;
358            float fRadius  = (float)res.R.AnimVal.Value;
359
360            float fEffectiveCX = fCenterX;
361            float fEffectiveCY = fCenterY;
362            float fEffectiveFX = fFocusX;
363            float fEffectiveFY = fFocusY;
364            float fEffectiveRadiusX = fRadius;
365            float fEffectiveRadiusY = fRadius;
366
367            if (res.GradientUnits.AnimVal.Equals(SvgUnitType.ObjectBoundingBox))
368            {
369                fEffectiveCX = bounds.Left + fCenterX * (bounds.Width);
370                fEffectiveCY = bounds.Top + fCenterY * (bounds.Height);
371                fEffectiveFX = bounds.Left + fFocusX * (bounds.Width);
372                fEffectiveFY = bounds.Top + fFocusY * (bounds.Height);
373                fEffectiveRadiusX = fRadius * bounds.Width;
374                fEffectiveRadiusY = fRadius * bounds.Height;
375            }
376
377            GraphicsPath gp = new GraphicsPath();
378            gp.AddEllipse(fEffectiveCX - fEffectiveRadiusX,
379                fEffectiveCY - fEffectiveRadiusY, 2 * fEffectiveRadiusX, 2 * fEffectiveRadiusY);
380
381            PathGradientBrush brush = new PathGradientBrush(gp);
382
383            brush.CenterPoint = new PointF(fEffectiveFX, fEffectiveFY);
384
385            XmlNodeList stops = res.Stops;
386
387            ColorBlend cb = new ColorBlend();
388
389            List<Color> adjcolors    = new List<Color>();
390            List<float> adjpositions = new List<float>();
391            GetColorsAndPositions(stops, adjpositions, adjcolors);
392
393            // Need to invert the colors for some bizarre reason
394            adjcolors.Reverse();
395            adjpositions.Reverse();
396            for (int i = 0; i < adjpositions.Count; i++)
397            {
398                adjpositions[i] = 1 - adjpositions[i];
399
400            }
401
402            cb.Colors    = adjcolors.ToArray();
403            cb.Positions = adjpositions.ToArray();
404
405            brush.InterpolationColors = cb;
406
407            //      ISvgTransformable transElm = (ISvgTransformable)res;
408            //      SvgTransformList svgTList = (SvgTransformList)transElm.transform.AnimVal;
409            //      brush.Transform = svgTList.matrix.matrix;
410
411            if (res.GetPropertyValue("color-interpolation") == "linearRGB")
412            {
413                //GdipSetPathGradientGammaCorrection(brush, true);
414            }
415            else
416            {
417                //GdipSetPathGradientGammaCorrection(brush, false);
418            }
419
420            /*
421                   * How to do brush.GammaCorrection = true on a PathGradientBrush? / nikgus
422                   * */
423
424            return brush;
425        }
426
427        #endregion
428    }
429}
Note: See TracBrowser for help on using the repository browser.