How to smooth a freehand drawn SVG path?

后端 未结 3 887
暗喜
暗喜 2021-01-31 10:59

I am looking for a solution to convert a freehand, user drawn SVG path, consisting of lots auf LineTo segments, into a smoother one.

Preferred language would be JavaScri

3条回答
  •  闹比i
    闹比i (楼主)
    2021-01-31 11:46

    first of all, I would recommend using a good graphics library, such as raphael. It will simplify the process of actually using javascript to perform the drawing.

    A very simple method of smoothing is to convert all lineto commands with equivalent curveto commands and calculate some control points based on the angles of each line segment. For example,

    
    
    
    
     
    

    becomes

    
    
    
    
     
    

    Both of these should draw an equilateral triangle

    The next step would be to calculate the position of the control points. Generally, you will want the control points on either side of a smooth corner to fall on an imaginary line that passes through the vertex. In the case of the top point of the equilateral triangle, this would be horizontal line. After some manipulation, you can get something like this:

    
    
    
    
     
    

    The tricky part is calculating the control points, but that turns into not much more than a simple trig problem. As I mentioned previously, the goal here is to put the two control points on a line that bisects the corner vertex. For example, suppose we have two line segments:

    A. (0,0) to (3,2)
    B. (0,0) to (1,-4)
    
    the absolute angle of A is arctan(2/3) = 33.69 deg
    the absolute angle of B is arctan(-4/1) = -75.96 deg
    the bisection angle of AB is (33.69 + -75.96)/2 = -21.135
    the tangent angle is AB is (-21.135 + 90) = 68.865
    

    knowing the tangent angle, we can calculate the control point positions

    smoothness = radius = r
    tangent angle = T
    Vertex X = Xv
    Vertex Y = Yv
    
    Control Point 1:
    Xcp1 = cos(T)*r
    Ycp1 = sin(T)*r
    
    Control Point 2:
    Xcp2 = cos(T)*(-r)
    Ycp2 = sin(T)*(-r)
    

    The last problem is where to put each control point in the actual curveTo command:

    CX1 Y1 X2 Y2 X3 Y3
    

    X3 and Y3 define the vertex location. X1 Y1 and X2 Y2 define the control points. You can think of X1 Y1 as defining the vector of how to enter the vertex and X2 Y2 as defining the vector of how to leave. Now that you have the two control points you must decide on

    CXcp1 Ycp1 Xcp2 Ycp2 0 0
    

    or

    CXcp2 Ycp2 Xcp1 Ycp1 0 0
    

    this is an important decision. If you get them backwards, the shape will look like a loop. By this point you should be able to determine how this decision should be made...

    Again, this is a very simple solution, but it tends to look good for hand drawn paths. A better solution might take it a step further and move the intersection point inwards towards the concave section of each line segment intersection. This is quite a bit more challenging.

提交回复
热议问题