This is the second day of my participation in Gwen Challenge

Code github address

Open Git and see the code for a better understanding of this article

Github.com/ananananzhu…

Methods in Path

1. Reset path method
 public void reset()
Copy the code
2. Move the brush to the specified position (starting position)

The x and y coordinates of this method are absolute

public void moveTo(float x, float y)
Copy the code
3. Move the brush to the specified position (starting position)

Unlike 2, the x and y coordinates in this method are relative coordinates

public void rMoveTo(float dx, float dy)
Copy the code
4. Move path corresponding to 2

Absolute coordinates

 public void lineTo(float x, float y)
Copy the code
5. Move the path corresponding to 3

Relative coordinates

 public void rLineTo(float dx, float dy)
Copy the code
6. Second-order Bezier curves

Absolute coordinates

X1, y1: Control points of bezier curves

X2, y2: Terminal coordinates of the Bezier curve

public void quadTo(float x1, float y1, float x2, float y2)
Copy the code

Second order Bezier curve dynamic animation presentation

The yellow point in the figure is the control point of the second-order Bezier curve, which follows the finger movement and dynamically refreshes the shape of the second-order Bezier curve

7. Second-order Bezier curves

Relative coordinates

 public void rQuadTo(float dx1, float dy1, float dx2, float dy2)
Copy the code
8. Third-order Bezier curves

Absolute coordinates

X1, y1: the first control point of third-order Bessel curve

X2, y2: the second control point of third-order Bessel curve

X3, y3: terminus of third-order Bezier curves

 public void cubicTo(float x1, float y1, float x2, float y2,
                        float x3, float y3)
Copy the code

Third order Bezier curve dynamic animation

The two blue dots are the control points of the third-order Bezier curve, which dynamically changes shape as we move the control points

9. Third-order Bezier curves

Relative coordinates

 public void rCubicTo(float x1, float y1, float x2, float y2,
                         float x3, float y3)
Copy the code
Draw arcs
 public void arcTo(RectF oval, float startAngle, float sweepAngle,
                      boolean forceMoveTo)
Copy the code

Code sample

override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) canvas? .apply { path.reset() paint.color=Color.YELLOW canvas.drawCircle(250f,250f,150f,paint) paint.color=Color.RED val ovalRectf = RectF(100f, 100f, 400f, 400f) path.arcTo(ovalRectf, 0f, 120f) path.close() drawPath(path, paint) } }Copy the code

Effect: the red part of the arc is the effect we want to achieve, the yellow part is our arc corresponding to the whole circle only play a reference role

11. Offset path

The offset result is written to DST

 public void offset(float dx, float dy, @Nullable Path dst)
Copy the code
public void offset(float dx, float dy)
Copy the code
12. End the path, connecting the starting and ending points
public void close()
Copy the code

Algorithm between two Paths (path.op)

Public Boolean op(Path Path, op op)Copy the code

The following table is a description of the OP properties

field function
DIFFERENCE Path1 minus path2
INTERSECT Leave the area where path2 and path2 intersect
UNION Union of path1 and path2
XOR Contains path1 and path2 but does not include intersecting parts
REVERSE_DIFFERENCE Path2 minus path1
Code Example (branch name: PATH)
// Override fun onDraw(canvas: canvas?) { super.onDraw(canvas) path1.reset() path2.reset() canvas? .apply { path1.addCircle(200f, 200f, radius1, Direction.CW) path2.addCircle(400f, 400f, radius2, Direction.CW) path1.op(path2, ops) path1.close() path2.close() canvas.drawPath(path1, paint1) // canvas.drawPath(path2, Op (path2, ops), path2 will be drawn by default}}Copy the code

In this example, you can change the size of two circles by dragging the Seekbar, and you can see the effect by clicking the button’s popup list box to select different path.ops properties

Effect:

The Path Direction Direction

Multiple drawing methods for Path have the path. Direction parameter

1. PathDirectionCCW counterclockwise

The sample code

 path1.addRect(rect,Path.Direction.CCW)
Copy the code
2, PathDirectionCW clockwise

The sample code

 path1.addRect(rect,Path.Direction.CW)
Copy the code

The Path filled – FillType

The Path to fill

FillType is an enumeration that has four types

 public enum FillType {

        WINDING         (0),

        EVEN_ODD        (1),

        INVERSE_WINDING (2),

        INVERSE_EVEN_ODD(3);

    }
Copy the code

1, the WINDING

How to determine if the path area needs to be filled: Draw a ray out of the area because the path has a Direction (clockwise and counterclockwise path.direction). We assume that clockwise is positive and counterclockwise is negative, and if the absolute value of the resulting value is greater than 0 then the inner region should be filled, and if ==0 then the outer region should not be filled. Therefore, when the border intersecting the ray is in the opposite direction (one clockwise and one counterclockwise), it is positive and negative 0, and this area is the outer area that cannot be filled

In the same direction

Code:

override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) path1.reset() canvas? .apply { path1.addCircle(200f, 200f, 100f, Path.Direction.CW) path1.addCircle(300f, 300f, 150f, Path.Direction.CW) path1.fillType = Path.FillType.WINDING drawPath(path1, paint) } }Copy the code

Code implementation effect

In the opposite direction

The code shown

override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) path1.reset() canvas? .apply { path1.addCircle(200f, 200f, 100f, Path.Direction.CW) path1.addCircle(300f, 300f, 150f, Path.Direction.CCW) path1.fillType = Path.FillType.WINDING drawPath(path1, paint) } }Copy the code

Code implementation effect

2, INVERSE_WINDING

In the same direction

The code shown

override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) path1.reset() canvas? .apply { path1.addCircle(200f, 200f, 100f, Path.Direction.CW) path1.addCircle(300f, 300f, 150f, Path.Direction.CW) path1.fillType = Path.FillType.INVERSE_WINDING drawPath(path1, paint) } }Copy the code

Code implementation effect display

In the opposite direction

The code shown

override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) path1.reset() canvas? .apply { path1.addCircle(200f, 200f, 100f, Path.Direction.CW) path1.addCircle(300f, 300f, 150f, Path.Direction.CCW) path1.fillType = Path.FillType.INVERSE_WINDING drawPath(path1, paint) } }Copy the code

Code effect display

3, EVEN_ODD

Like WINDING, EVEN_ODD uses ray-drawing to determine whether it is an internally refillable area. If the ray intersects path with an even number of points, it belongs to the outer region and does not need to be filled. If it’s odd then it’s an inner region that needs to be filled. Effect drawing display:

Code display:

override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) path1.reset() canvas? .apply { path1.addCircle(200f, 200f, 100f, Path.Direction.CW) path1.addCircle(300f, 300f, 150f, Path.Direction.CW) path1.fillType = Path.FillType.EVEN_ODD drawPath(path1, paint) } }Copy the code

Code effect display

4, INVERSE_EVEN_ODD

The release is the opposite of the area EVEN_ODD is filled with code to show

override fun onDraw(canvas: Canvas?) { super.onDraw(canvas) path1.reset() canvas? .apply { path1.addCircle(200f, 200f, 100f, Path.Direction.CW) path1.addCircle(300f, 300f, 150f, Path.Direction.CW) path1.fillType = Path.FillType.INVERSE_EVEN_ODD drawPath(path1, paint) } }Copy the code

Code effect display

After the