Recent

Author Topic: Crescent Moon Bgrabmp: With some Extra Parameters and Save Png  (Read 1043 times)

Boleeman

  • Hero Member
  • *****
  • Posts: 715
Thanks to bobby100 for the update to the Crescent Moon type curve.

Now I would like to try to make the Soddy Crescent Curve which is described here:

https://www.codeproject.com/Articles/808880/Soddy-Crescent-Construction

As shown in the attached png, the Radii of the filled circles get smaller progressively as they go around the circumference of the smaller circle. Lots of maths involved to get the radius sizes of each circle correct.



« Last Edit: August 31, 2024, 06:02:30 am by Boleeman »

bobby100

  • Sr. Member
  • ****
  • Posts: 260
    • Malzilla
Re: Moon Crescent Curve: How to Make it ?
« Reply #1 on: June 30, 2024, 05:52:16 pm »
Move the center of the inner circle a bit more down and probably increase the diameter of the inner circle.

Edit: if that doesn't work, you'll probably need an ellipsis instead of the inner circle.

bobby100

  • Sr. Member
  • ****
  • Posts: 260
    • Malzilla
Re: Moon Crescent Curve: How to Make it ?
« Reply #2 on: June 30, 2024, 06:38:18 pm »
So:
- I've got your clipping, but you lost the black inner line. You'll need to draw an extra arc there
- I've re-arranged your code. Don't put the same code in 3 procedures. Make an extra procedure with the code (ReDraw in my code) and call it from that 3 procedures.

Boleeman

  • Hero Member
  • *****
  • Posts: 715
Re: Moon Crescent Curve: How to Make it ?
« Reply #3 on: July 01, 2024, 05:51:27 am »
Many Thanks for that update bobby100. Much Appreciated.

It was very late yesterday and had to go to bed, so sorry about disappearing so suddenly.

I also added a TSpinedit Rotate, a fill colour selection Tcolorbutton and a save to png for the Crescent Moon.
« Last Edit: July 01, 2024, 06:51:08 am by Boleeman »

Boleeman

  • Hero Member
  • *****
  • Posts: 715
Re: Crescent Moon Done: Soddy Crescent how to make it ?
« Reply #4 on: July 01, 2024, 06:32:00 am »
Here is the CSharp code of the Soddy Crescent:

Code: Pascal  [Select][+][-]
  1.  using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.Linq;
  5. using System.Text;
  6.  
  7. namespace SoddyCrescent
  8. {
  9.     public class SoddyCircle
  10.     {
  11.         public readonly double curvature;
  12.         public readonly double radius;
  13.  
  14.         public SoddyCircle(double curvature)
  15.         {
  16.             this.curvature = curvature;
  17.             radius = Math.Abs(1 / curvature);
  18.         }
  19.  
  20.         public override string ToString()
  21.         {
  22.             string s = String.Format("curvature: {0}\t\tradius: {1}", curvature, radius);
  23.             return s;
  24.         }
  25.  
  26.     } // class SoddyCircle
  27.  
  28.  
  29.     public class ForthSoddyCircle
  30.     {
  31.         private List<SoddyCircle> forthSoddyCircle;
  32.         public ReadOnlyCollection<SoddyCircle> rdOnlyForthSoddyCircle
  33.         {
  34.             get { return forthSoddyCircle.AsReadOnly(); }
  35.         }
  36.  
  37.         public ForthSoddyCircle(double curvature1, double curvature2, double curvature3)
  38.         {
  39.             forthSoddyCircle = new List<SoddyCircle>();
  40.             double K1K2_K2K3_K3K1_Prod = curvature1 * curvature2 + curvature2 * curvature3 + curvature3 * curvature1;
  41.             if ((K1K2_K2K3_K3K1_Prod < 0) &&
  42.                 (Math.Abs(K1K2_K2K3_K3K1_Prod)<.0000000000001))
  43.             {
  44.                 K1K2_K2K3_K3K1_Prod = 0.0;
  45.             }
  46.             if (K1K2_K2K3_K3K1_Prod < 0)
  47.             {
  48.                 throw new System.ArgumentException("Impossible curvatures for Soddy circles.");
  49.             }
  50.             forthSoddyCircle.Add(new SoddyCircle(curvature1 + curvature2 + curvature3 + 2 * (Math.Sqrt(K1K2_K2K3_K3K1_Prod))));
  51.             if (K1K2_K2K3_K3K1_Prod == 0) return;
  52.             forthSoddyCircle.Add(new SoddyCircle(curvature1 + curvature2 + curvature3 - 2 * (Math.Sqrt(K1K2_K2K3_K3K1_Prod))));
  53.         }
  54.  
  55.     } // class ForthSoddyCircle
  56.  
  57. }
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79.  
  80.  
  81.  
  82.  
  83. using System;
  84. using System.Windows;
  85. using System.Collections.Generic;
  86. using System.Collections.ObjectModel;
  87. using System.Linq;
  88. using System.Text;
  89.  
  90. namespace SoddyCrescent
  91. {
  92.     public class CoOrd
  93.     {
  94. /*
  95.         public override string ToString()
  96.         {
  97.             return (String.Format("({0},{1})", x, y));
  98.         }
  99. */
  100.         public static double DistanceSquared(Point p0, Point p1)
  101.         {
  102.  //           return (Math.Pow(p0.x - p1.x, 2) + Math.Pow(p0.y - p1.y, 2));
  103.             return (p0.X - p1.X) * (p0.X - p1.X) + (p0.Y - p1.Y) * (p0.Y - p1.Y);
  104.         }
  105.     } // class CoOrd
  106.  
  107.  
  108.     public class MyCircle
  109.     {
  110.         public double radius;
  111.         public Point center;
  112.         // kappa = .5522847490
  113.         private static double Kappa = (Math.Sqrt(2) - 1) * 4 / 3;
  114.  
  115.         public MyCircle()
  116.         {
  117.             radius = 0;
  118.             center = new Point();
  119.         }
  120.  
  121.         public MyCircle(double radius, Point coord)
  122.         {
  123.             this.radius = radius;
  124.             center = coord;
  125.         }
  126.  
  127.         public override string ToString()
  128.         {
  129.             string s = String.Format("radius: {0}\t\t", radius);
  130.             s += "center: " + center.ToString();
  131.             return s;
  132.         }
  133.  
  134.         public Curve GenerateCurve()
  135.         {
  136.             Curve curve = new Curve(4);   // 4 bezier segments in curve for circle
  137.             // start and endpoint for each segment
  138.             curve.startPoint = new Point(center.X, center.Y - radius);  //down from center
  139.             curve.points[2] =  new Point(center.X + radius, center.Y);  //right from center
  140.             curve.points[5] =  new Point(center.X, center.Y + radius);  //up from center
  141.             curve.points[8] =  new Point(center.X - radius, center.Y);  //left from center
  142.             curve.points[11] = new Point(center.X, center.Y - radius);  //down from center (same as start point)
  143.  
  144.             double rk = radius * Kappa;
  145.             curve.points[0] = new Point(curve.startPoint.X + rk, curve.startPoint.Y);
  146.             curve.points[1] = new Point(curve.points[2].X, curve.points[2].Y - rk);
  147.  
  148.             curve.points[3] = new Point(curve.points[2].X, curve.points[2].Y + rk);
  149.             curve.points[4] = new Point(curve.points[5].X + rk, curve.points[5].Y);
  150.  
  151.             curve.points[6] = new Point(curve.points[5].X - rk, curve.points[5].Y);
  152.             curve.points[7] = new Point(curve.points[8].X, curve.points[8].Y + rk);
  153.  
  154.             curve.points[9] = new Point(curve.points[8].X, curve.points[8].Y - rk);
  155.             curve.points[10] = new Point(curve.points[11].X-rk, curve.points[11].Y);
  156.  
  157.             return curve;
  158.         }
  159.     } // class MyCircle
  160.  
  161.  
  162.     public class Intersect
  163.     {
  164.         private List<Point> intersects;
  165.         public ReadOnlyCollection<Point> rdOnlyIntersects
  166.         {
  167.             get { return intersects.AsReadOnly(); }
  168.         }
  169.  
  170.         public Intersect()
  171.         {
  172.             intersects = new List<Point>();
  173.         }
  174.         public void AddIntersect(Point intersect)
  175.         {
  176.             intersects.Add(intersect);
  177.         }
  178.  
  179.     } // class Intersect
  180.  
  181.  
  182.     public class CircleIntersect
  183.     // Given 2 circles P0 and P1
  184.     // p2 is the CoOrd of the point at the intersection of the line
  185.     // between the circle centers and the chord line between the intersections.
  186.     // the p1-->p2 distance is a
  187.     // the p0-->p2 distance is b
  188.     // h is the p2-->intersect distance on the chord
  189.     {
  190.         private MyCircle P0, P1;
  191.         private double dSquared;    //distance squared between centers
  192.         private double d;           //distance between centers
  193.         private double a, b;
  194.         private Point p2;
  195.         private double h;
  196.         private double dx, dy;
  197.         public Intersect intersects;
  198.  
  199.         public CircleIntersect(MyCircle P0, MyCircle P1)
  200.         {
  201.             intersects = new Intersect();
  202.             p2 = new Point();
  203.             this.P0 = P0;
  204.             this.P1 = P1;
  205.             dSquared = CoOrd.DistanceSquared(P0.center, P1.center);
  206.             d = Math.Sqrt(dSquared);
  207.  
  208.             if (d > P1.radius + P0.radius)
  209.                 return;
  210.             if (d < Math.Abs(P1.radius - P0.radius))
  211.                 return;
  212.  
  213.             b = (P0.radius * P0.radius - P1.radius * P1.radius + dSquared) / (2 * d);
  214.             a = d - b;
  215.             double dx = P0.center.X - P1.center.X;
  216.             p2.X = P1.center.X + (a / d) * dx;
  217.             double dy = P0.center.Y - P1.center.Y;
  218.             p2.Y = P1.center.Y + (a / d) * dy;
  219.  
  220.             h = Math.Sqrt(P1.radius * P1.radius - a * a);
  221.             dx = (P1.center.Y - P0.center.Y) * (h / d);
  222.             dy = (P1.center.X - P0.center.X) * (h / d);
  223.             intersects.AddIntersect(new Point((p2.X + dx), (p2.Y - dy)));
  224.             intersects.AddIntersect(new Point((p2.X - dx), (p2.Y + dy)));
  225.         }
  226.  
  227.         private string CheckIntersect(Point i, MyCircle P)
  228.         {
  229.             Double sum;
  230.             sum = (i.X - P.center.X) * (i.X - P.center.X);
  231.             sum += (i.Y - P.center.Y) * (i.Y - P.center.Y);
  232.             sum -= P.radius * P.radius;
  233.             return ("Check sum: " + sum);
  234.         }
  235.  
  236.         public void ShowIntersect()
  237.         {
  238.             Console.WriteLine("====  CircleIntersect ====");
  239.             Console.WriteLine("\tcircle P0: " + P0.ToString());
  240.             Console.WriteLine("\tcircle P1: " + P1.ToString());
  241.             Console.WriteLine("\tdSquared: " + dSquared);
  242.             Console.WriteLine("\td: " + d);
  243.             Console.WriteLine("\ta: " + a);
  244.             Console.WriteLine("\tb: " + b);
  245.             Console.WriteLine("p2: " + p2.ToString());
  246.             Console.WriteLine("h: " + h);
  247.             ReadOnlyCollection<Point> inter = intersects.rdOnlyIntersects;
  248.             for (int i = 0; i < inter.Count; i++)
  249.             {
  250.                 Console.WriteLine("\tintersect: " + inter[i].ToString());
  251.                 Console.WriteLine(CheckIntersect(inter[i], P0));
  252.                 Console.WriteLine(CheckIntersect(inter[i], P1));
  253.             }
  254.             Console.WriteLine("\t\t\t====");
  255.  
  256.         }
  257.  
  258.     } // class CircleIntersect
  259.  
  260. }
  261.  
  262.  
  263.  
  264.  
  265.  
  266.  
  267.  
  268.  
  269.  
  270.  
  271.  
  272.  
  273.  
  274.  
  275.  
  276.  
  277. using System;
  278. using System.Collections.Generic;
  279. using System.Collections.ObjectModel;
  280. using System.Linq;
  281. using System.Text;
  282. using System.Windows;
  283. using System.Windows.Controls;
  284.  
  285. namespace SoddyCrescent
  286. {
  287.     public class GrafCan
  288.     {
  289.         private double xScale;
  290.         public double XScale
  291.         { get { return xScale; } }
  292.         private double yScale;
  293.         public double YScale
  294.         { get { return yScale; } }
  295.  
  296.         private double yMax;
  297.         public double YMAx
  298.         { get { return yMax; } }
  299.         private double yMin;
  300.         public double YMin
  301.         { get { return yMin; } }
  302.  
  303.         private double actWidth;
  304.         public double ActWidth
  305.         { get { return actWidth; } }
  306.  
  307.         private double actHeight;
  308.         public double ActHeight
  309.         { get { return actHeight; } }
  310.  
  311.         private double yZero;
  312.  
  313.         public Canvas can;
  314.  
  315.  
  316.  
  317.  
  318.         public GrafCan(double actWidth, double actHeight, double yMax, double yMin, Canvas can)
  319.         {
  320.             this.can = can;
  321.             this.actWidth = actWidth;
  322.             this.actHeight = actHeight;
  323.             this.yMax = yMax;
  324.             this.yMin = yMin;
  325.  
  326.             yScale = actHeight / (yMax - yMin);
  327.             xScale = actWidth;
  328.             //            xScale = actWidth / 2 * Math.PI;
  329.  
  330.             yZero = yMax * yScale;
  331.         } // ctor
  332.  
  333.  
  334.         public Point GraphPoint(Point curvePoint)
  335.         {
  336.             Point grafPoint = new Point();
  337.             grafPoint.X = curvePoint.X * xScale;
  338.             grafPoint.Y = yZero - curvePoint.Y * yScale;
  339.             return grafPoint;
  340.         } // GraphPoint()
  341.  
  342.     }
  343. }
  344.  
  345.  
  346.  
  347.  
  348.  
  349.  
  350.  
  351.  
  352.  
  353.  
  354.  
  355.  
  356.  
  357.  
  358.  
  359.  
  360.  
  361.  
  362.  
  363. using System;
  364. using System.Collections.Generic;
  365. using System.Linq;
  366. using System.Text;
  367. using System.Windows;
  368. using System.Windows.Controls;
  369. using System.Windows.Media;
  370. using System.Windows.Shapes;
  371.  
  372. namespace SoddyCrescent
  373. {
  374.     public class CurveStyle
  375.     {
  376.         public double strokeThickness;
  377.         public Brush brush;
  378.         public Brush fillBrush;
  379.  
  380.         public CurveStyle()
  381.         {
  382.             strokeThickness = 1;
  383.             brush = new SolidColorBrush(Colors.Black);
  384.         } //ctor
  385.  
  386.         public CurveStyle(double strokeThickness, Brush brush)
  387.         {
  388.             this.strokeThickness = strokeThickness;
  389.             this.brush = brush;
  390.         } //ctor
  391.     } // class Style
  392.  
  393.  
  394.  
  395.     public class Curve
  396.     {
  397.         public static List<Point> bPts = new List<Point>();            //for debugging!!!!!
  398.  
  399.         public Point startPoint;
  400.         public Point[] points;
  401.         public Boolean hasBeenAdded;    //to canvas children
  402.         public int addedAt;             //canvas child number
  403.         public CurveStyle style;
  404.  
  405.  
  406.         public Curve(int numberPoints)
  407.         {
  408.             points = new Point[numberPoints * 3];   //each Bezier in a polybs has 3 points
  409.             style = new CurveStyle();
  410.         }
  411.  
  412.         private Curve()
  413.         {
  414.             style = new CurveStyle();
  415.         }
  416.  
  417.  
  418.  
  419.         public Curve Graf(GrafCan gc)
  420.         {
  421.             Curve grafCurve = new Curve();
  422.             grafCurve.style = style;
  423.             grafCurve.points = new Point[points.Length];
  424.             grafCurve.startPoint = gc.GraphPoint(startPoint);
  425.             for (int i = 0; i < points.Length; i++)
  426.                 grafCurve.points[i] = gc.GraphPoint(points[i]);
  427.             return grafCurve;
  428.         } // Graf()
  429.  
  430.  
  431.         public PathGeometry ToGeometry(Curve c)
  432.         {
  433.             PolyBezierSegment pbs = new PolyBezierSegment(c.points, true);
  434.  
  435.             //put single PolyBezierSegment into a PathSegmentCollection
  436.             PathSegmentCollection psc = new PathSegmentCollection();
  437.             psc.Add(pbs);
  438.  
  439.             PathFigure pf = new PathFigure();
  440.             pf.StartPoint = c.startPoint;
  441.             pf.Segments = psc;
  442.  
  443.             PathFigureCollection pfc = new PathFigureCollection();
  444.             pfc.Add(pf);
  445.  
  446.             PathGeometry pg = new PathGeometry();
  447.             pg.Figures = pfc;
  448.  
  449.             return pg;
  450.         }
  451.  
  452.  
  453.         public void ToString()
  454.         {
  455.             Console.WriteLine("Curve - " + points.Length + " DataFormat points");
  456.             Console.WriteLine("\tstartPoint: " + startPoint.ToString());
  457.             for (int i = 1; i <= points.Length; i++)
  458.             {
  459.                 Console.WriteLine("\tP" + i + ": " + points[i - 1].ToString());
  460.             }
  461.         }
  462.  
  463.  
  464.         public static void ShowPoints(GrafCan gc, Point[] points)
  465.         {
  466.             Path path = new Path();
  467.             path.Stroke = Brushes.Green;
  468.             path.StrokeThickness = 1;
  469.             GeometryGroup gg = new GeometryGroup();
  470.  
  471.             foreach (Point p in points)
  472.             {
  473.                 Point gp = gc.GraphPoint(p);
  474.                 EllipseGeometry eg = new EllipseGeometry(gp, 3, 3);
  475.                 gg.Children.Add(eg);
  476.             }
  477.             path.Data = gg;
  478.             gc.can.Children.Add(path);
  479.         } // ShowPoints()
  480.  
  481.  
  482.         public void ShowControlPoints(GrafCan gc)
  483.         {
  484.             Curve cGraf = Graf(gc);           //create new curve adjusted to geometry
  485.             Path path = new Path();
  486.             path.Stroke = Brushes.Green;
  487.             path.StrokeThickness = 1;
  488.  
  489.             GeometryGroup gg = new GeometryGroup();
  490.             foreach (Point p in cGraf.points)
  491.             {
  492.                 EllipseGeometry eg = new EllipseGeometry(p, 3, 3);
  493.                 gg.Children.Add(eg);
  494.             }
  495.             path.Data = gg;
  496.             gc.can.Children.Add(path);
  497.  
  498.             Path endPointPath = new Path();
  499.             endPointPath.Stroke = Brushes.Black;
  500.             endPointPath.StrokeThickness = 2;
  501.             GeometryGroup egg = new GeometryGroup();
  502.             EllipseGeometry egStart = new EllipseGeometry(cGraf.startPoint, 3, 3);
  503.             egg.Children.Add(egStart);
  504.  
  505.             for (int i = 2; i < cGraf.points.Length; i += 3)
  506.             {
  507.                 EllipseGeometry eg = new EllipseGeometry(cGraf.points[i], 3, 3);
  508.                 egg.Children.Add(eg);
  509.             }
  510.             endPointPath.Data = egg;
  511.             gc.can.Children.Add(endPointPath);
  512.  
  513.         } // ShowControlPoints()
  514.  
  515.  
  516.         public void AddCurveToCan(GrafCan gc)
  517.         {
  518.             Curve cGraf = Graf(gc);           //create new curve adjusted to geometry
  519.             //           cGraf.ToString();
  520.             //           MyPath.Data = c.ToGeometry(cGraf);
  521.             Path p = new Path();
  522.  
  523.             //            p.Fill = new SolidColorBrush(Colors.LightCyan);
  524.  
  525.             p.StrokeThickness = style.strokeThickness;
  526.             //            p.Fill =
  527.             p.Stroke = style.brush;
  528.             p.Fill = style.fillBrush;
  529.             //            p.Stretch = Stretch.Fill;
  530.             p.Data = ToGeometry(cGraf);
  531.             //            gc.can.Children.Add(p);
  532.             if (!hasBeenAdded)
  533.             {
  534.                 gc.can.Children.Add(p);
  535.                 hasBeenAdded = true;
  536.                 addedAt = gc.can.Children.Count - 1;
  537.             }
  538.             else
  539.             {
  540.                 gc.can.Children.RemoveAt(addedAt);
  541.                 gc.can.Children.Insert(addedAt, p);
  542.             }
  543.         } // AddCurveToCan()
  544.  
  545.  
  546.         public Curve CopyCurveAndMove(double dx, double dy)
  547.         {
  548.             Curve cc = new Curve(points.Length / 3);
  549.             cc.style.strokeThickness = style.strokeThickness;
  550.             cc.style.brush = style.brush;
  551.             cc.startPoint.X = startPoint.X + dx;
  552.             cc.startPoint.Y = startPoint.Y + dy;
  553.             int i = 0;
  554.             foreach (Point p in points)
  555.             {
  556.                 cc.points[i].X = p.X + dx;
  557.                 cc.points[i].Y = p.Y + dy;
  558.                 i++;
  559.             }
  560.             return cc;
  561.         } // CopyCurveAndMove()
  562.  
  563.  
  564.     } // class Curve
  565. }
  566.  
  567.  


Attached is my failed attempt at converting the CSharp version to Lazarus.
Not getting the right curves happening.
grafcan.pas does the scaling
forthsoddycircle.pas creates the 4th and new circles according to the algorithm k4 = k1 + k2 + k3 +/- 2(k1*k2+k1*k3+k2*k3)^0.5
soddycrescent.pas calculates the intersections
curve.pas creates the curve points and moves them

Also attached is:

The screenshot of the CSharp working version that I tried to convert to Lazarus.
Animation showing the formation of the curve in the CSharp version.  (last attached gif)




« Last Edit: July 01, 2024, 09:10:48 am by Boleeman »

Boleeman

  • Hero Member
  • *****
  • Posts: 715
Re: Crescent Moon Done: Soddy Crescent how to make it ?
« Reply #5 on: August 30, 2024, 11:32:51 am »
Never got that CSharp Soddy Crescent conversion to Lazarus to work properly to make that cool Soddy Crescent. Frustrated!


But found and made the Bgrabmp Crescent Moon Shadow from bgrabmp Wiki page.

Boleeman

  • Hero Member
  • *****
  • Posts: 715
Re: Crescent Moon Bgrabmp
« Reply #6 on: August 31, 2024, 06:01:50 am »
Some extra parameters added to vary the Crescent and also save to png.


I like how layer.EraseEllipseAntialias was used to erase the pre-drawn ellipse.
Also like how the curve resizes when the size of the form is changed.
« Last Edit: August 31, 2024, 06:11:32 am by Boleeman »

 

TinyPortal © 2005-2018