Address: http://www.antigrain.com/research/
Bezier_interpolation/index.html # page_bezier_interpolation
Interpolation with bezr curves besell Interpolation
A very simple method of smoothing polygons is a very simple polygon smoothing method.
Translation: Tang Feng
Previously, a discussion on Comp. Graphic. Algorithms was about how to use curves to interpolation polygon so that the final curve is smooth and can pass through all vertices. Gernot Hoffmann suggests using the famous B-Spline for interpolation. Here is his article. B-spline works well here, and it looks like an elastic r fixed on the polygon vertex ).
But I have a bold speculation that there must be a simpler method. For example, use a cubic beserver curve (cubic bezr) for approximation. The beiser curve has two fixed points (starting point and ending point), plus two control points (CP) that determine the shape of the curve ). You can find more information about the beiser curve in search engines. For example, you can refer to the Paul Bourke site. Now the anchor (Fixed Point) of the beiser curve, that is, a pair of vertices of the polygon, the question is, how do we calculate the position of the control point? I ran xara X and drew the graph on the right. It was very simple, so I decided to calculate their coordinates. Obviously, the vertex between the two control points of the two adjacent edges of a polygon and the two control points should be in a straight line. Only in this way can the two adjacent Interpolation Curves be smoothly connected together. Therefore, these two control points should be symmetric relative to the vertex. However, they are not all ......, Because the real symmetry requires that the distance between them and the center point should be equal, but this is not exactly the case for us. At first, I tried to calculate the angle bisector of the two sides of the polygon, and then put the control point on the vertical line of the angle bisector. However, we can see from the figure that the line of the control point is not always perpendicular to the angle bisector.
In the end, I found a very simple method without any complicated mathematical computation. First, we calculate the point of all edges of a polygon, AI.
Connect the adjacent edge midpoint to obtain many line segments, which are recorded as ci. Calculate the Bi point by using the graph.
In the last step, you only need to translate CI. The translation path is the path from Bi to the corresponding Vertex on each line segment. In this way, we have calculated the control points of the beiser curve, and the smooth results look great.
Here we can also make a small improvement, because we have obtained a straight line that determines the control point, so we can move the control point on this line as needed, this changes the status of the interpolation curve. I used a coefficient K related to the control point and the initial distance of the vertex to move the control point along a straight line. The farther the control point is from the vertex, the sharper the image looks.
The following is the SVG lion drawn by using the original shape and the system K = 1.0 besell interpolation.
The following is an enlarged image.
This method also applies to self-related polygon. The following example shows that the result is very interesting:
This method is only exploratory and empirical. It may be wrong from a strict mathematical model. However, the results in actual use are good enough, and this method only requires the minimum amount of computing. The following code is used to draw the image of the lion above. These codes are not optimized and are only used for demonstration. Some variables are calculated twice. In the actual program, if the same variable value is used in consecutive steps, we can cache the variable value for reuse (to avoid repeated calculation ).
// Assume we need to calculate the control// points between (x1,y1) and (x2,y2).// Then x0,y0 - the previous vertex,// x3,y3 - the next one. double xc1 = (x0 + x1) / 2.0;double yc1 = (y0 + y1) / 2.0;double xc2 = (x1 + x2) / 2.0;double yc2 = (y1 + y2) / 2.0;double xc3 = (x2 + x3) / 2.0;double yc3 = (y2 + y3) / 2.0; double len1 = sqrt((x1-x0) * (x1-x0) + (y1-y0) * (y1-y0));double len2 = sqrt((x2-x1) * (x2-x1) + (y2-y1) * (y2-y1));double len3 = sqrt((x3-x2) * (x3-x2) + (y3-y2) * (y3-y2)); double k1 = len1 / (len1 + len2);double k2 = len2 / (len2 + len3); double xm1 = xc1 + (xc2 - xc1) * k1;double ym1 = yc1 + (yc2 - yc1) * k1; double xm2 = xc2 + (xc3 - xc2) * k2;double ym2 = yc2 + (yc3 - yc2) * k2; // Resulting control points. Here smooth_value is mentioned// above coefficient K whose value should be in range [0...1].ctrl1_x = xm1 + (xc2 - xm1) * smooth_value + x1 - xm1;ctrl1_y = ym1 + (yc2 - ym1) * smooth_value + y1 - ym1; ctrl2_x = xm2 + (xc2 - xm2) * smooth_value + x2 - xm2;ctrl2_y = ym2 + (yc2 - ym2) * smooth_value + y2 - ym2;
The following code is used:
// Number of intermediate points between two source ones,// Actually, this value should be calculated in some way,// Obviously, depending on the real length of the curve.// But I don't know any elegant and fast solution for this// problem.#define NUM_STEPS 20 void curve4(Polygon* p, double x1, double y1, //Anchor1 double x2, double y2, //Control1 double x3, double y3, //Control2 double x4, double y4) //Anchor2{ double dx1 = x2 - x1; double dy1 = y2 - y1; double dx2 = x3 - x2; double dy2 = y3 - y2; double dx3 = x4 - x3; double dy3 = y4 - y3; double subdiv_step = 1.0 / (NUM_STEPS + 1); double subdiv_step2 = subdiv_step*subdiv_step; double subdiv_step3 = subdiv_step*subdiv_step*subdiv_step; double pre1 = 3.0 * subdiv_step; double pre2 = 3.0 * subdiv_step2; double pre4 = 6.0 * subdiv_step2; double pre5 = 6.0 * subdiv_step3; double tmp1x = x1 - x2 * 2.0 + x3; double tmp1y = y1 - y2 * 2.0 + y3; double tmp2x = (x2 - x3)*3.0 - x1 + x4; double tmp2y = (y2 - y3)*3.0 - y1 + y4; double fx = x1; double fy = y1; double dfx = (x2 - x1)*pre1 + tmp1x*pre2 + tmp2x*subdiv_step3; double dfy = (y2 - y1)*pre1 + tmp1y*pre2 + tmp2y*subdiv_step3; double ddfx = tmp1x*pre4 + tmp2x*pre5; double ddfy = tmp1y*pre4 + tmp2y*pre5; double dddfx = tmp2x*pre5; double dddfy = tmp2y*pre5; int step = NUM_STEPS; // Suppose, we have some abstract object Polygon which // has method AddVertex(x, y), similar to LineTo in // many graphical APIs. // Note, that the loop has only operation add! while(step--) { fx += dfx; fy += dfy; dfx += ddfx; dfy += ddfy; ddfx += dddfx; ddfy += dddfy; p->AddVertex(fx, fy); } p->AddVertex(x4, y4); // Last step must go exactly to x4, y4}
You can download an example of a lion painting that can run, rotate and scale it, or generate random polygon. Click and drag it to rotate and scale the image around the center. Right click and drag from left to right to change the system number K. K = 1 is about 100 pixels away from the left side of the window. Each double-click generates a Random Polygon. You can also rotate, scale, and change the K value of these polygon.