Simulation implementation of C # cardinal spline curve (corresponding to DrawCurve of graphics)

Source: Internet
Author: User

In C # 's drawing function, there is a function drawcurve that draws a spline, and when only the pen and point arrays are passed in, the cardinal spline is used to draw the curve. If you just draw a spline, the function is already satisfied. But the project requires not only to draw curves, but also to simulate the curve in the form of squares. For this reason, it is necessary to know how the spline is drawn, only to know what points it has, and then use the lattice to simulate it.

At first, a very crude method was used, that is, using DrawCurve to draw into the image in memory, then remove the black and white points from the image, and then form a matrix of black and white points, and then use these matrix points corresponding to the pixel points to draw the squares. Did a simple implementation, but the effect is not ideal. There are several reasons.

1. The constant use of memory to draw into the image consumes a lot of memory.

2. It is difficult to determine the range of a collection when using pixel points to capture the points of a matrix.

3. At least a double-loop traversal of the pixel x and Y is required to achieve this, so that the time complexity increases with the increase of X and Y.

A simulation of the implementation, after the transformation, the initial achievement of the purpose. Take a look at the simulated and drawcurve fitting, see.


Note: The black part of the figure is drawn using drawcurve, and the white part in the middle of the black line is simulated. Judging from the results of the test, the degree of compliance is more ideal. The following is the implementation code.

Using system;using system.collections.generic;using system.drawing;using system.linq;using System.Text;namespace splinetest{//<summary>///spline curve. Each spline consists of 4 control points//</summary> public class Spline {///<summary>//////. Between the point PK and pk+1, a number of sample points will be generated.        So the "U" will grow from 0.00F to 0.05F.        </summary> private static readonly int _samplepointcount = 20;        <summary>//////</summary> private static readonly float _tension = 0.0F in the cardinality algorithm;        #region attribute private PointF _startcontrolpoint;            <summary>///"Pk-1" point (Start Control Point)///</summary> public PointF Startcontrolpoint {            get {return this._startcontrolpoint;            } set {this._startcontrolpoint = value;        }} private PointF _startpoint; <summary>//"Pk" point (starting point)       </summary> public PointF StartPoint {get {return thi            S._startpoint;            } set {this._startpoint = value;        }} private PointF _endpoint;            <summary>///"pk+1" point (end point)///</summary> public PointF EndPoint {            get {return this._endpoint;            } set {this._endpoint = value;        }} private PointF _endcontrolpoint;            <summary>///"pk+2" point (end Control point)///</summary> public PointF Endcontrolpoint {            get {return this._endcontrolpoint;            } set {this._endcontrolpoint = value;        }} private pointf[] _ctrlpoints;    <summary>    Curve point (Control point and Analog sample)///</summary> public pointf[] Ctrlpoints {get {            return this._ctrlpoints;        }} private bool _isfirst = false;        <summary>////identifies if the current spline is the first, if M_startcontrolpoint and M_startpoint will be the same.        Because we need 4 points between PK and pk+1 to determine the spline, we need to add a point manually before the Pk-1 point.        This allows us to draw a spline between Pk-1 and pk+1.        Similarly, the pk+2 point of the last spline will be the same as its "pk+1" point,///so that we can draw a spline between pk+1 and pk+2.            </summary> public bool IsFirst {get {return this._isfirst;            } set {This._isfirst = value;            }} #endregion public Spline () {_startcontrolpoint = new PointF ();            _startpoint = new PointF ();            _endpoint = new PointF ();            _endcontrolpoint = new PointF (); _ctrlpoints = new Pointf[_samplepointcount + 1];           for (int i = 0; i < _ctrlpoints.length; i++) {_ctrlpoints[i] = new PointF (); }}///<summary>//Add joints.        Add a new control point to the list of control points and update the previous spline. </summary>//<param name= "Prevspline" > Previous spline </param>//<param name= "Currentpoi NT "> Current point </param> public void Addjoint (Spline prevspline, PointF currentpoint) {//previous spline            (Prevspline) is null, stating that there is only one point in the list of control points, so the 4 control points are the same. When a 2nd and subsequent control point is added to the list of control points, the pk+1 and pk+2 points of the 1th spline need to be updated if (null = = Prevspline) {This._start                ControlPoint = Currentpoint;                This._startpoint = Currentpoint;                This._endpoint = Currentpoint;                This._endcontrolpoint = Currentpoint;            This._isfirst = true;            The previous spline is not NULL, so update the list of control points for the previous spline and update the list of control points for the current spline, as well as the else//curve.           {//The previous spline is the 1th spline, updating its pk+1 and pk+2 points     if (true = = Prevspline._isfirst) {this._startcontrolpoint = Prevspline.startcontro                    Lpoint;                    This._startpoint = Prevspline.startpoint;                    This._endpoint = Currentpoint;                    This._endcontrolpoint = Currentpoint;                    Generatesamplepoint ();                Return } else///the previous spline is not the 1th spline, just update its pk+2 point {prevspline.endcontrolpoint = Curre                    Ntpoint;                    Prevspline.generatesamplepoint ();                    Simulating the spline of the current spline this._startcontrolpoint = Prevspline._startpoint;                    This._startpoint = Prevspline._endpoint;                    This._endpoint = Currentpoint;                    This._endcontrolpoint = Currentpoint;                Generatesamplepoint ();        }}}///<summary>///Use cardinality algorithm to generate sample points///</summary>public void Generatesamplepoint () {PointF-startcontrolpoint = this.            Startcontrolpoint; PointF StartPoint = this.            StartPoint; PointF EndPoint = this.            EndPoint; PointF Endcontrolpoint = this.            Endcontrolpoint;            Float step = 1.0F/(float) _samplepointcount;            float uvalue = 0.00F;  for (int i = 0; i < _samplepointcount; i++) {PointF pointnew = Generatesimulatepoint (Uvalue,                Startcontrolpoint, StartPoint, EndPoint, Endcontrolpoint); This.                Ctrlpoints[i] = pointnew;            Uvalue + = step; } this.        Ctrlpoints[_ctrlpoints.length-1] = EndPoint;         }///<summary> draw splines////</summary>//<param name= "G" ></param>            public void Draw (Graphics g, pen pen) {for (int i = 0; i < _ctrlpoints.length-1; i++) {PointF lastpoint = _ctrlpoints[i];                PointF Nextpoint = _ctrlpoints[i + 1];            G.drawline (pen, Lastpoint, Nextpoint);        }} #region Generatesimulatepoint//<summary>////To generate a curve simulation point between StartPoint and endpoint </summary>//<param name= "U" > variable between 0 and 1 </param>//<param name= "Startcontrol Point > Start point startPoint to help determine the appearance of the curve </param>//<param name= "StartPoint" > The starting point of the target curve startPoint when u=0 , the return result is the starting point startpoint</param>//<param name= "EndPoint" > The end point of the target curve EndPoint, when u=1, returns the result as the end point Endpoint</pa ram>//<param name= "Endcontrolpoint" > Control points after node startpoint to help determine the appearance of the curve </param>//<return                                S> returns points between StartPoint and endpoint </returns> private PointF Generatesimulatepoint (float u,  PointF Startcontrolpoint, PointF startPoint, PointF                  EndPoint,              PointF endcontrolpoint) {float s = (1-_tension)/2;            PointF resultpoint = new PointF ();            Resultpoint.x = Calculateaxiscoordinate (Startcontrolpoint.x, Startpoint.x, Endpoint.x, EndControlPoint.X, S, u);            Resultpoint.y = Calculateaxiscoordinate (Startcontrolpoint.y, Startpoint.y, Endpoint.y, EndControlPoint.Y, S, u);        return resultpoint;        }///<summary>//Calculate axis coordinates///</summary>//<param name= "a" ></param> <param name= "B" ></param>//<param name= "C" ></param>//<param name=        "D" ></param>//<param name= "s" ></param>//<param name= "U" ></param> <returns></returns> Private float calculateaxiscoordinate (float A, float B, float C, float D, FL            Oat S, float u) {float result = 0.0F; result = A * (2 * s * u* U-s * U * u * u-s * u) + b * ((2-S) * u * U * U + (s-3) * U * U + 1) + c * (            (s-2) * u * U * U + (3-2 * s) * U * U + S * u) + d * (S * u * u * u-s * u * u);        return result; } #endregion///<summary>//Get points on the spline///</summary>//<param name= "G" ></param>//<param name= "pen" ></param>//<param name= "points" &GT;&LT;/PARAM&G        T public static list<pointf> Fetchpoints (pointf[] points) {if (points = = NULL | | points.            Length <= 0) {return null;            } list<spline> _splines = new list<spline> ();            Spline splinenew = null;            Spline lastnew = null; foreach (PointF nowpoint in points) {if (null = = _splines | | 0 = = _splines. Count) {splinenew = nEW Spline ();                    Splinenew.addjoint (null, nowpoint); _splines.                ADD (splinenew);                    } else {splinenew = new Spline (); Lastnew = _splines[_splines.                    Count-1] as Spline;                    Splinenew.addjoint (Lastnew, nowpoint); _splines.                ADD (splinenew);            };            } list<pointf> _points = new list<pointf> (); foreach (Spline Spline in _splines) {if (Spline.                IsFirst) {continue; } foreach (PointF point in spline. ctrlpoints) {if (_points.                    Contains (point)) {continue; } _points.                ADD (point);        }} return _points; }}///<summary>//Graphics extensionExhibition//</summary> public static class Graphicsextension {///<summary>//Draw splines        </summary>//<param name= "G" ></param>//<param name= "pen" ></param> <param name= "points" ></param> public static void DrawSpline (this Graphics g, pen pen, pointf[            ] {points) {if (g = = null) {return;            } if (pen = = null) {return; } if (points = = NULL | | points.            Length <= 0) {return;            } list<spline> _splines = new list<spline> ();            Spline splinenew = null;            Spline lastnew = null; foreach (PointF nowpoint in points) {if (null = = _splines | | 0 = = _splines.                    Count) {splinenew = new Spline (); Splinenew.addjoint (nUll, Nowpoint); _splines.                ADD (splinenew);                    } else {splinenew = new Spline (); Lastnew = _splines[_splines.                    COUNT-1];                    Splinenew.addjoint (Lastnew, nowpoint); _splines.                ADD (splinenew);            }} Spline Spline = null; for (int i = 0; i < _splines. Count;                i++) {spline = _splines[i]; if (spline.                IsFirst) {continue; } spline.            Draw (g, pen); }        }    }}
Note:

1.Spline part of the most core algorithm is calculateaxiscoordinate, online there are many similar implementations, but are not ideal, this is the more ideal one.

2. In order to facilitate direct invocation in the graphics, an extension method DrawSpline is added to the graphics, so that it can be called as called DrawCurve, which is G. DrawSpline (pen,points).

3. After plotting the spline curve, it is necessary to get the point that it simulates, so a fetchpoints method is added in spline.

Reprint please indicate the source http://blog.csdn.net/xxdddail/article/details/47662983.

Copyright NOTICE: This article for Bo Master original article, without Bo Master permission not reproduced.

Simulation implementation of C # cardinal spline curve (corresponding to DrawCurve of graphics)

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.