Jump to content

Archimedean Spiral (May 6, 2022)


Recommended Posts

Draws an Archimedean spiral

 

Screenshot-ArchimedeanSpiral.png.3bed7a6df11cda279a050be28a6ef0be.png

Found in Effects > Render

 

Versions:

1.0(20220502) - Initial Release

1.1(20220503) - Add option for Initial Loop Number / larger Initial Point Offset increments

1.2(20220506) - Fix Initial Point Offset "typo"

 

C# Code Snippet (Modified from CodeLab generated code)

License: LPGL-3.0

 

Spoiler
        protected override void OnRender(Rectangle[] rois, int startIndex, int length)
        {
            if (length == 0 || IsCancelRequested)
            {
                return;
            }

            using CancellationTokenSource cts = new();
            using System.Timers.Timer timer = new(20);
            timer.AutoReset = true;
            timer.Elapsed += (s, e) =>
            {
                if (IsCancelRequested)
                {
                    cts.Cancel();
                }
            };
            timer.Start();

            try
            {
                Render(DstArgs.Surface, SrcArgs.Surface, EnvironmentParameters.SelectionBounds, cts.Token);
            }
            catch (OperationCanceledException)
            {
            }
            timer.Stop();
        }

        #region UICode
        private DoubleSliderControl loops = 5; // [2,1000] Loops
        private IntSliderControl spacing = 25; // [1,100] Loop Spacing
        private DoubleSliderControl step = 10; // [1,360] Point Alignment
        private ListBoxControl offsetType = 1; // |Initial Loop Number|Initial Point Offset
        private IntSliderControl offset = 0; // [0,100]
        private DoubleSliderControl tension = 0.5; // [0,1] Line Curvature
        private IntSliderControl width = 1; // [1,100] Line Width
        private CheckboxControl clockwise = true; // Clockwise
        private PanSliderControl center = Pair.Create(0.000, 0.000); // Center
        private AngleControl rotation = 0; // [0,360] Rotation
        #endregion

        private PointF[] cachedPoints;
        private State cachedState;

        private void Render(Surface dst, Surface src, Rectangle rect, CancellationToken token)
        {
            dst.CopySurface(src, rect.Location, rect);

            using Graphics g = new RenderArgs(dst).Graphics;
            using Region gClipRegion = new(rect);

            g.Clip = gClipRegion;
            g.SmoothingMode = SmoothingMode.AntiAlias;
            g.TextRenderingHint = TextRenderingHint.AntiAlias;

            float centerX = (float)(rect.Left + (center.First + 1) / 2 * rect.Width);
            float centerY = (float)(rect.Top + (center.Second + 1) / 2 * rect.Height);

            g.TranslateTransform(centerX, centerY);
            g.RotateTransform((float)-rotation);

            if (IsCancelRequested) return;

            PointF[] points;
            State state = new(this);

            if (state.Equals(cachedState))
            {
                points = cachedPoints;
            }
            else
            {
                double a = offsetType == 1 ? offset : offset * spacing;
                double b = spacing / 360.0;
                double toRad = Math.PI / (clockwise ? 180 : -180);

                points = Enumerable
                    .Range(0, (int)(loops * 360 / step + 1))
                    .AsParallel()
                    .AsOrdered()
                    .WithCancellation(token)
                    .Select(i =>
                    {
                        double theta = i * step;
                        double r = a + b * theta;
                        double rad = theta * toRad;

                        (double sin, double cos) = Math.SinCos(rad);
                        float x = (float)(r * cos);
                        float y = (float)(r * sin);
                        return new PointF(x, y);
                    })
                    .ToArray();
            }

            using Pen pen = new(EnvironmentParameters.PrimaryColor, width);
            pen.StartCap = LineCap.Round;
            pen.EndCap = LineCap.Round;
            g.DrawCurve(pen, points, (float)tension);

            cachedPoints = points;
            cachedState = state;
        }

        internal class State
        {
            private readonly double loops;
            private readonly int spacing;
            private readonly double step;
            private readonly byte offsetType;
            private readonly int offset;
            private readonly bool clockwise;

            public State(ArchimedeanSpiralEffectPlugin plugin)
            {
                loops = plugin.loops;
                spacing = plugin.spacing;
                step = plugin.step;
                offsetType = plugin.offsetType;
                offset = plugin.offset;
                clockwise = plugin.clockwise;
            }

            public override bool Equals(object obj)
            {
                return obj is State state &&
                       loops == state.loops &&
                       spacing == state.spacing &&
                       step == state.step &&
                       offsetType == state.offsetType &&
                       offset == state.offset &&
                       clockwise == state.clockwise;
            }

            public override int GetHashCode()
            {
                return HashCode.Combine(loops, spacing, step, offsetType, offset, clockwise);
            }
        }
    }

 

 

 

 

ArchimedeanSpiral.zip

Edited by VeLC
Version 1.2
  • Like 5
  • Upvote 1
Link to comment
Share on other sites

  • VeLC changed the title to Archimedean Spiral (May 3, 2022)
  • VeLC changed the title to Archimedean Spiral (May 6, 2022)

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...