VeLC Posted May 6, 2022 Share Posted May 6, 2022 (edited) Draws text along an Archimedean spiral path 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 May 13, 2022 by VeLC Version 1.2 3 3 1 Quote Link to comment Share on other sites More sharing options...
VeLC Posted May 7, 2022 Author Share Posted May 7, 2022 Version 1.1 - Add Loop Spacing and Initial Point Offset options 4 Quote Link to comment Share on other sites More sharing options...
VeLC Posted May 13, 2022 Author Share Posted May 13, 2022 Version 1.2 - Code Update and slightly shorter UI 1 1 Quote Link to comment Share on other sites More sharing options...
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.