Jump to content

Spiral Text (May 13, 2022)


Recommended Posts

Draws text along an Archimedean spiral path

 

Screenshot-SpiralText.png.12e6f18bb881782266026d6bc7379145.png

Found in Effects > Text Formations. The menu name is "Spir@l Text" to differentiate with dpy's SpiralText

 

Versions:

1.0(20220506) - Initial Release

1.1(20220507) - Add Loop Spacing and Initial Point Offset options

1.2(20220507) - Code Update and slightly shorter UI

 

CodeLab Code

License: LPGL-3.0

 

Spoiler
// Name: Spir@l Text
// Submenu: Text Formations
// Author: Louie Velarde
// Title: Spiral Text
// Version: 1.2
// Desc: Draws text along an Archimedean spiral path
// Keywords: spiral text
// URL: https://forums.getpaint.net/topic/119979-spiral-text/
// Help: https://forums.getpaint.net/topic/119979-spiral-text/
// Force Single Render Call
#region UICode
TextboxControl text = ""; // [18000]
IntSliderControl repeat = 1; // [1,1800] Repeat
FontFamily fontFamily = new FontFamily("Arial"); //
IntSliderControl fontSize = 12; // [8,288]
CheckboxControl bold = false; // Bold
PanSliderControl center = Pair.Create(0.000, 0.000); // Center
ListBoxControl spiralType = 0; // |Clockwise Inwards|Clockwise Outwards|Counterclockwise Inwards|Counterclockwise Outwards
AngleControl rotation = 0; // [0,360]
CheckboxControl useFontSize = true; // Calculate spacing based on font size
IntSliderControl charSpacing = 0; // [0, 100] Character Spacing
DoubleSliderControl lineSpacing = 1; // [0.001, 10] {useFontSize} Line Spacing
IntSliderControl lineHeight = 25; // [1, 100] {!useFontSize} Loop Spacing
ListBoxControl offsetType = 0; // |Initial Loop Number | Initial Point Offset
IntSliderControl offset = 2; // [0,100]
#endregion

bool rendered;

void PreRender(Surface dst, Surface src)
{
    rendered = false;
}

void Render(Surface dst, Surface src, Rectangle rect)
{
    if (rendered) return;
    rendered = true;

    rect = EnvironmentParameters.SelectionBounds;
    dst.CopySurface(src, rect.Location, rect);

    if (text == string.Empty) return;

    StringBuilder sb = new StringBuilder(text);
    for (int i = 2; i <= repeat; ++i)
    {
        if (IsCancelRequested) return;
        sb.Append(text);
    }

    using (Graphics g = new RenderArgs(dst).Graphics)
    using (Region gClipRegion = new Region(rect))
    using (Font font = new Font(fontFamily, fontSize, bold ? FontStyle.Bold : FontStyle.Regular))
    using (Brush brush = new SolidBrush(EnvironmentParameters.PrimaryColor))
    {
        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);

        StringFormat format = new StringFormat(StringFormat.GenericTypographic);
        format.FormatFlags |= StringFormatFlags.MeasureTrailingSpaces;
        format.FormatFlags |= StringFormatFlags.NoFontFallback;
        
        double totalHeights = 0;
        SizeF[] sizes = new SizeF[sb.Length];

        for (int i = 0; i < sb.Length; ++i)
        {
            if (IsCancelRequested) return;
            sizes[i] = g.MeasureString(sb[i].ToString(), font, short.MaxValue, format);
            totalHeights += sizes[i].Height;
        }
        double avgHeight = totalHeights / sb.Length;
        double b = (useFontSize ? avgHeight * lineSpacing : lineHeight) / Math.PI / 2;

        double len = offsetType == 0
            ? b * Math.Pow(Math.PI * 2 * offset, 2) / 2
            : offset * offset / b / 2;
        double radian = Math.Sqrt(2 * len / b);

        if (spiralType < 2)
        {
            g.RotateTransform((float) (90 - rotation));
        }
        else
        {
            g.RotateTransform((float) (-90 - rotation));
        }

        if ((spiralType & 1) == 0)
        {
            int s = spiralType == 0 ? -1 : 1;
            double radius = b * radian * s;
            double toDeg = 180 / Math.PI * s;

            int startIndex = sb.Length - 1;
            g.DrawString(sb[startIndex].ToString(), font, brush, sizes[startIndex].Width / -2, (float) (radius - avgHeight / 2), format);

            for (int i = startIndex - 1; i >=0; --i)
            {
                if (IsCancelRequested) return;
                len += sizes[i + 1].Width / 2 + charSpacing + sizes[i].Width / 2;

                double newRadian = Math.Sqrt(2 * len / b);
                g.RotateTransform((float) ((newRadian - radian) * toDeg));

                radius = b * newRadian * s;
                g.DrawString(sb[i].ToString(), font, brush, sizes[i].Width / -2, (float) (radius - avgHeight / 2), format);

                radian = newRadian;
            }
        }
        else
        {
            int s = spiralType == 1 ? -1 : 1;
            double radius = b * radian * s;
            double toDeg = 180 / Math.PI * s * -1;

            g.DrawString(sb[0].ToString(), font, brush, sizes[0].Width / -2, (float) (radius - avgHeight / 2), format);

            for (int i = 1; i < sb.Length; ++i)
            {
                if (IsCancelRequested) return;
                len += sizes[i - 1].Width / 2 + charSpacing + sizes[i].Width / 2;

                double newRadian = Math.Sqrt(2 * len / b);
                g.RotateTransform((float) ((newRadian - radian) * toDeg));

                radius = b * newRadian * s;
                g.DrawString(sb[i].ToString(), font, brush, sizes[i].Width / -2, (float) (radius - avgHeight / 2), format);

                radian = newRadian;
            }
        }
    }
}

 

 

 

SpiralText.zip

Edited by VeLC
Version 1.2
  • Like 3
  • Upvote 3
  • You're a Smart Cookie! 1
Link to comment
Share on other sites

  • VeLC changed the title to Spiral Text (May 7 ,2022)
  • VeLC changed the title to Spiral Text (May 13, 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...