SvgRandomArt.cs
//
// This code is part of GrapeCity Documents for Imaging samples.
// Copyright (c) GrapeCity, Inc. All rights reserved.
//
using System;
using System.IO;
using System.Drawing;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using GrapeCity.Documents.Drawing;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Imaging;
using GrapeCity.Documents.Svg;
using GCTEXT = GrapeCity.Documents.Text;
using GCDRAW = GrapeCity.Documents.Drawing;
using GcImagingWeb.Samples.Common;

namespace GcImagingWeb.Samples
{
    // This sample generates some random abstract art using the SVG path API
    // provided by GcSvgDocument.
    public class SvgRandomArt
    {
        private System.Random rnd = Util.NewRandom();

        public GcBitmap GenerateImage(Size pixelSize, float dpi, bool opaque, string[] sampleParams = null)
        {
            using var svgDoc = new GcSvgDocument();
            var svg = svgDoc.RootSvg;
            svg.ViewBox = new SvgViewBox(0, 0, 100, 100);

            // Random art:
            for (int i = 0; i < rnd.Next(6, 12); i++)
                AddFigure(svg, rnd);

            // Border:
            svg.Children.Add(new SvgRectElement()
            {
                Width = new SvgLength(100),
                Height = new SvgLength(100),
                Stroke = new SvgPaint(Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256))),
                Fill = SvgPaint.None
            });
            // Clip:
            svg.Clip = new SvgClip(new SvgLength(0), new SvgLength(0), new SvgLength(100), new SvgLength(100));

            // Render the SVG image:
            var bmp = new GcBitmap(pixelSize.Width, pixelSize.Height, opaque, dpi, dpi);
            using var g = bmp.CreateGraphics(Color.White);
            var s = svgDoc.GetIntrinsicSize(SvgLengthUnits.Pixels);

            var margin = dpi * 0.75f;
            var rect = new RectangleF(margin, margin, pixelSize.Width - margin * 2, pixelSize.Width - margin * 2);
            g.DrawSvg(svgDoc, rect);

            // Done:
            return bmp;
        }

        int Next100()
        {
            return rnd.Next(100);
        }

        void AddFigure(SvgSvgElement svg, System.Random rnd)
        {
            var pb = new SvgPathBuilder();
            var startX = Next100();
            var startY = Next100();
            pb.AddMoveTo(false, startX, startY);
            for (int i = 0; i < rnd.Next(20, 80); ++i)
                AddCurve(pb, rnd);
            pb.AddCurveTo(false, Next100(), Next100(), Next100(), Next100(), startX, startY);

            svg.Children.Add(new SvgPathElement()
            {
                FillRule = SvgFillRule.EvenOdd,
                Fill = new SvgPaint(Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256))),
                Stroke = new SvgPaint(Color.FromArgb(rnd.Next(256), rnd.Next(256), rnd.Next(256))),
                StrokeWidth = new SvgLength(rnd.Next(20) / 10f, SvgLengthUnits.Percentage),
                PathData = pb.ToPathData(),
                FillOpacity = Next100() / 100f,
                StrokeOpacity = Next100() / 100f,
            });
        }

        void AddCurve(SvgPathBuilder pb, System.Random _rnd)
        {
            switch (_rnd.Next(5))
            {
                case 0:
                    pb.AddCurveTo(false, Next100(), Next100(), Next100(), Next100(), Next100(), Next100());
                    break;
                case 1:
                    pb.AddSmoothCurveTo(false, Next100(), Next100(), Next100(), Next100());
                    break;
                case 2:
                    pb.AddQuadraticBezierCurveTo(false, Next100(), Next100(), Next100(), Next100());
                    break;
                case 3:
                    pb.AddSmoothQuadraticBezierCurveTo(false, Next100(), Next100());
                    break;
                case 4:
                    pb.AddEllipticalArc(false, Next100(), Next100(), _rnd.Next(360),
                        _rnd.Next(2) == 0 ? GCDRAW.ArcSize.Small : GCDRAW.ArcSize.Large,
                        _rnd.Next(2) == 0 ? GCDRAW.SweepDirection.Clockwise : GCDRAW.SweepDirection.CounterClockwise,
                        Next100(), Next100());
                    break;
            }
        }
    }
}