美文网首页
flutter贝塞尔曲线

flutter贝塞尔曲线

作者: ChaosHeart | 来源:发表于2020-09-01 10:39 被阅读0次

    1.贝塞尔曲线

    class Path extends NativeFieldWrapperClass2 {
      /// Create a new empty [Path] object.
      @pragma('vm:entry-point')
      Path() { _constructor(); }
      void _constructor() native 'Path_constructor';
    
      /// Creates a copy of another [Path].
      ///
      /// This copy is fast and does not require additional memory unless either
      /// the `source` path or the path returned by this constructor are modified.
      factory Path.from(Path source) {
        return source._clone();
      }
      Path _clone() native 'Path_clone';
    
      /// Determines how the interior of this path is calculated.
      ///
      /// Defaults to the non-zero winding rule, [PathFillType.nonZero].
      PathFillType get fillType => PathFillType.values[_getFillType()];
      set fillType(PathFillType value) => _setFillType(value.index);
    
      int _getFillType() native 'Path_getFillType';
      void _setFillType(int fillType) native 'Path_setFillType';
    
      /// Starts a new sub-path at the given coordinate.
      void moveTo(double x, double y) native 'Path_moveTo';
    
      /// Starts a new sub-path at the given offset from the current point.
      void relativeMoveTo(double dx, double dy) native 'Path_relativeMoveTo';
    
      /// Adds a straight line segment from the current point to the given
      /// point.
      void lineTo(double x, double y) native 'Path_lineTo';
    
      /// Adds a straight line segment from the current point to the point
      /// at the given offset from the current point.
      void relativeLineTo(double dx, double dy) native 'Path_relativeLineTo';
    
      /// Adds a quadratic bezier segment that curves from the current
      /// point to the given point (x2,y2), using the control point
      /// (x1,y1).
      void quadraticBezierTo(double x1, double y1, double x2, double y2) native 'Path_quadraticBezierTo';
    
      /// Adds a quadratic bezier segment that curves from the current
      /// point to the point at the offset (x2,y2) from the current point,
      /// using the control point at the offset (x1,y1) from the current
      /// point.
      void relativeQuadraticBezierTo(double x1, double y1, double x2, double y2) native 'Path_relativeQuadraticBezierTo';
    
      /// Adds a cubic bezier segment that curves from the current point
      /// to the given point (x3,y3), using the control points (x1,y1) and
      /// (x2,y2).
      void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3) native 'Path_cubicTo';
    
      /// Adds a cubic bezier segment that curves from the current point
      /// to the point at the offset (x3,y3) from the current point, using
      /// the control points at the offsets (x1,y1) and (x2,y2) from the
      /// current point.
      void relativeCubicTo(double x1, double y1, double x2, double y2, double x3, double y3) native 'Path_relativeCubicTo';
    
      /// Adds a bezier segment that curves from the current point to the
      /// given point (x2,y2), using the control points (x1,y1) and the
      /// weight w. If the weight is greater than 1, then the curve is a
      /// hyperbola; if the weight equals 1, it's a parabola; and if it is
      /// less than 1, it is an ellipse.
      void conicTo(double x1, double y1, double x2, double y2, double w) native 'Path_conicTo';
    
      /// Adds a bezier segment that curves from the current point to the
      /// point at the offset (x2,y2) from the current point, using the
      /// control point at the offset (x1,y1) from the current point and
      /// the weight w. If the weight is greater than 1, then the curve is
      /// a hyperbola; if the weight equals 1, it's a parabola; and if it
      /// is less than 1, it is an ellipse.
      void relativeConicTo(double x1, double y1, double x2, double y2, double w) native 'Path_relativeConicTo';
    
      /// If the `forceMoveTo` argument is false, adds a straight line
      /// segment and an arc segment.
      ///
      /// If the `forceMoveTo` argument is true, starts a new sub-path
      /// consisting of an arc segment.
      ///
      /// In either case, the arc segment consists of the arc that follows
      /// the edge of the oval bounded by the given rectangle, from
      /// startAngle radians around the oval up to startAngle + sweepAngle
      /// radians around the oval, with zero radians being the point on
      /// the right hand side of the oval that crosses the horizontal line
      /// that intersects the center of the rectangle and with positive
      /// angles going clockwise around the oval.
      ///
      /// The line segment added if `forceMoveTo` is false starts at the
      /// current point and ends at the start of the arc.
      void arcTo(Rect rect, double startAngle, double sweepAngle, bool forceMoveTo) {
        assert(_rectIsValid(rect));
        _arcTo(rect.left, rect.top, rect.right, rect.bottom, startAngle, sweepAngle, forceMoveTo);
      }
      void _arcTo(double left, double top, double right, double bottom,
                  double startAngle, double sweepAngle, bool forceMoveTo) native 'Path_arcTo';
    
      /// Appends up to four conic curves weighted to describe an oval of `radius`
      /// and rotated by `rotation`.
      ///
      /// The first curve begins from the last point in the path and the last ends
      /// at `arcEnd`. The curves follow a path in a direction determined by
      /// `clockwise` and `largeArc` in such a way that the sweep angle
      /// is always less than 360 degrees.
      ///
      /// A simple line is appended if either either radii are zero or the last
      /// point in the path is `arcEnd`. The radii are scaled to fit the last path
      /// point if both are greater than zero but too small to describe an arc.
      ///
      void arcToPoint(Offset arcEnd, {
        Radius radius = Radius.zero,
        double rotation = 0.0,
        bool largeArc = false,
        bool clockwise = true,
        }) {
        assert(_offsetIsValid(arcEnd));
        assert(_radiusIsValid(radius));
        _arcToPoint(arcEnd.dx, arcEnd.dy, radius.x, radius.y, rotation,
                    largeArc, clockwise);
      }
      void _arcToPoint(double arcEndX, double arcEndY, double radiusX,
                       double radiusY, double rotation, bool largeArc,
                       bool clockwise) native 'Path_arcToPoint';
    
    
      /// Appends up to four conic curves weighted to describe an oval of `radius`
      /// and rotated by `rotation`.
      ///
      /// The last path point is described by (px, py).
      ///
      /// The first curve begins from the last point in the path and the last ends
      /// at `arcEndDelta.dx + px` and `arcEndDelta.dy + py`. The curves follow a
      /// path in a direction determined by `clockwise` and `largeArc`
      /// in such a way that the sweep angle is always less than 360 degrees.
      ///
      /// A simple line is appended if either either radii are zero, or, both
      /// `arcEndDelta.dx` and `arcEndDelta.dy` are zero. The radii are scaled to
      /// fit the last path point if both are greater than zero but too small to
      /// describe an arc.
      void relativeArcToPoint(Offset arcEndDelta, {
        Radius radius = Radius.zero,
        double rotation = 0.0,
        bool largeArc = false,
        bool clockwise = true,
        }) {
        assert(_offsetIsValid(arcEndDelta));
        assert(_radiusIsValid(radius));
        _relativeArcToPoint(arcEndDelta.dx, arcEndDelta.dy, radius.x, radius.y,
                            rotation, largeArc, clockwise);
      }
      void _relativeArcToPoint(double arcEndX, double arcEndY, double radiusX,
                               double radiusY, double rotation,
                               bool largeArc, bool clockwise)
                               native 'Path_relativeArcToPoint';
    
      /// Adds a new sub-path that consists of four lines that outline the
      /// given rectangle.
      void addRect(Rect rect) {
        assert(_rectIsValid(rect));
        _addRect(rect.left, rect.top, rect.right, rect.bottom);
      }
      void _addRect(double left, double top, double right, double bottom) native 'Path_addRect';
    
      /// Adds a new sub-path that consists of a curve that forms the
      /// ellipse that fills the given rectangle.
      ///
      /// To add a circle, pass an appropriate rectangle as `oval`. [Rect.fromCircle]
      /// can be used to easily describe the circle's center [Offset] and radius.
      void addOval(Rect oval) {
        assert(_rectIsValid(oval));
        _addOval(oval.left, oval.top, oval.right, oval.bottom);
      }
      void _addOval(double left, double top, double right, double bottom) native 'Path_addOval';
    
      /// Adds a new sub-path with one arc segment that consists of the arc
      /// that follows the edge of the oval bounded by the given
      /// rectangle, from startAngle radians around the oval up to
      /// startAngle + sweepAngle radians around the oval, with zero
      /// radians being the point on the right hand side of the oval that
      /// crosses the horizontal line that intersects the center of the
      /// rectangle and with positive angles going clockwise around the
      /// oval.
      void addArc(Rect oval, double startAngle, double sweepAngle) {
        assert(_rectIsValid(oval));
        _addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
      }
      void _addArc(double left, double top, double right, double bottom,
                   double startAngle, double sweepAngle) native 'Path_addArc';
    
      /// Adds a new sub-path with a sequence of line segments that connect the given
      /// points.
      ///
      /// If `close` is true, a final line segment will be added that connects the
      /// last point to the first point.
      ///
      /// The `points` argument is interpreted as offsets from the origin.
      void addPolygon(List<Offset> points, bool close) {
        assert(points != null);
        _addPolygon(_encodePointList(points), close);
      }
      void _addPolygon(Float32List points, bool close) native 'Path_addPolygon';
    
      /// Adds a new sub-path that consists of the straight lines and
      /// curves needed to form the rounded rectangle described by the
      /// argument.
      void addRRect(RRect rrect) {
        assert(_rrectIsValid(rrect));
        _addRRect(rrect._value32);
      }
      void _addRRect(Float32List rrect) native 'Path_addRRect';
    
      /// Adds a new sub-path that consists of the given `path` offset by the given
      /// `offset`.
      ///
      /// If `matrix4` is specified, the path will be transformed by this matrix
      /// after the matrix is translated by the given offset. The matrix is a 4x4
      /// matrix stored in column major order.
      void addPath(Path path, Offset offset, {Float64List matrix4}) {
        assert(path != null); // path is checked on the engine side
        assert(_offsetIsValid(offset));
        if (matrix4 != null) {
          assert(_matrix4IsValid(matrix4));
          _addPathWithMatrix(path, offset.dx, offset.dy, matrix4);
        } else {
          _addPath(path, offset.dx, offset.dy);
        }
      }
      void _addPath(Path path, double dx, double dy) native 'Path_addPath';
      void _addPathWithMatrix(Path path, double dx, double dy, Float64List matrix) native 'Path_addPathWithMatrix';
    
      /// Adds the given path to this path by extending the current segment of this
      /// path with the the first segment of the given path.
      ///
      /// If `matrix4` is specified, the path will be transformed by this matrix
      /// after the matrix is translated by the given `offset`.  The matrix is a 4x4
      /// matrix stored in column major order.
      void extendWithPath(Path path, Offset offset, {Float64List matrix4}) {
        assert(path != null); // path is checked on the engine side
        assert(_offsetIsValid(offset));
        if (matrix4 != null) {
          assert(_matrix4IsValid(matrix4));
          _extendWithPathAndMatrix(path, offset.dx, offset.dy, matrix4);
        } else {
          _extendWithPath(path, offset.dx, offset.dy);
        }
      }
      void _extendWithPath(Path path, double dx, double dy) native 'Path_extendWithPath';
      void _extendWithPathAndMatrix(Path path, double dx, double dy, Float64List matrix) native 'Path_extendWithPathAndMatrix';
    
      /// Closes the last sub-path, as if a straight line had been drawn
      /// from the current point to the first point of the sub-path.
      void close() native 'Path_close';
    
      /// Clears the [Path] object of all sub-paths, returning it to the
      /// same state it had when it was created. The _current point_ is
      /// reset to the origin.
      void reset() native 'Path_reset';
    
      /// Tests to see if the given point is within the path. (That is, whether the
      /// point would be in the visible portion of the path if the path was used
      /// with [Canvas.clipPath].)
      ///
      /// The `point` argument is interpreted as an offset from the origin.
      ///
      /// Returns true if the point is in the path, and false otherwise.
      bool contains(Offset point) {
        assert(_offsetIsValid(point));
        return _contains(point.dx, point.dy);
      }
      bool _contains(double x, double y) native 'Path_contains';
    
      /// Returns a copy of the path with all the segments of every
      /// sub-path translated by the given offset.
      Path shift(Offset offset) {
        assert(_offsetIsValid(offset));
        return _shift(offset.dx, offset.dy);
      }
      Path _shift(double dx, double dy) native 'Path_shift';
    
      /// Returns a copy of the path with all the segments of every
      /// sub-path transformed by the given matrix.
      Path transform(Float64List matrix4) {
        assert(_matrix4IsValid(matrix4));
        return _transform(matrix4);
      }
      Path _transform(Float64List matrix4) native 'Path_transform';
    
      /// Computes the bounding rectangle for this path.
      ///
      /// A path containing only axis-aligned points on the same straight line will
      /// have no area, and therefore `Rect.isEmpty` will return true for such a
      /// path. Consider checking `rect.width + rect.height > 0.0` instead, or
      /// using the [computeMetrics] API to check the path length.
      ///
      /// For many more elaborate paths, the bounds may be inaccurate.  For example,
      /// when a path contains a circle, the points used to compute the bounds are
      /// the circle's implied control points, which form a square around the circle;
      /// if the circle has a transformation applied using [transform] then that
      /// square is rotated, and the (axis-aligned, non-rotated) bounding box
      /// therefore ends up grossly overestimating the actual area covered by the
      /// circle.
      // see https://skia.org/user/api/SkPath_Reference#SkPath_getBounds
      Rect getBounds() {
        final Float32List rect = _getBounds();
        return Rect.fromLTRB(rect[0], rect[1], rect[2], rect[3]);
      }
      Float32List _getBounds() native 'Path_getBounds';
    
      /// Combines the two paths according to the manner specified by the given
      /// `operation`.
      ///
      /// The resulting path will be constructed from non-overlapping contours. The
      /// curve order is reduced where possible so that cubics may be turned into
      /// quadratics, and quadratics maybe turned into lines.
      static Path combine(PathOperation operation, Path path1, Path path2) {
        assert(path1 != null);
        assert(path2 != null);
        final Path path = Path();
        if (path._op(path1, path2, operation.index)) {
          return path;
        }
        throw StateError('Path.combine() failed.  This may be due an invalid path; in particular, check for NaN values.');
      }
      bool _op(Path path1, Path path2, int operation) native 'Path_op';
    
      /// Creates a [PathMetrics] object for this path.
      ///
      /// If `forceClosed` is set to true, the contours of the path will be measured
      /// as if they had been closed, even if they were not explicitly closed.
      PathMetrics computeMetrics({bool forceClosed = false}) {
        return PathMetrics._(this, forceClosed);
      }
    }
    

    2.绘制贝塞尔曲线

    1.要绘制贝塞尔线,我们需要四个点:起点终点两个控制点,如下图所示。移动控制点会改变曲线的斜率。您可以在此在线工具中使用控制点。

    我们可以使用类Path的cubicTo方法绘制贝塞尔曲线:

    void cubicTo(double x1, double y1, double x2, double y2, double x3, double y3)
    

    使用控制点(x1,y1)和(x2,y2)添加从当前点到给定点(x3,y3)的曲线的三次贝塞尔曲线段。

    如您所见,该cubicTo方法接受三个参数。其中两个是控制点,最后一个参数是终点。起点是您的笔已经位于画布上的位置。

    不要忘记在画布坐标中,左上角是(0,0)点,右下角是(size.width,size.height)。因此,请尝试相应地调整四点:

    //自绘接口
    void paint(Canvas canvas, Size size) {
    
      var paint = Paint();
    
      paint.color = Colors.lightBlue;
      paint.style = PaintingStyle.stroke;
      paint.strokeWidth = 3;
    
      var startPoint = Offset(0, size.height / 2);
      var controlPoint1 = Offset(size.width / 4, size.height / 3);
      var controlPoint2 = Offset(3 * size.width / 4, size.height / 3);
      var endPoint = Offset(size.width, size.height / 2);
    
      var path = Path();
      path.moveTo(startPoint.dx, startPoint.dy);
      path.cubicTo(controlPoint1.dx, controlPoint1.dy,
          controlPoint2.dx, controlPoint2.dy,
          endPoint.dx, endPoint.dy);
    
      canvas.drawPath(path, paint);
    }
    

    请记住,paint对象就像我们的笔,我们将其颜色设置为蓝色,宽度设置为3。

    我们用path对象描述了bezier路径。该moveTo方法已用于将笔移动到路径的起​​点。然后我们调用cubicTo方法来定义控制点和终点。之后,我们使用该drawPath方法绘制了路径。

    贝塞尔曲线参考:
    https://www.jianshu.com/p/90be43fc7bee

    ///推荐一些曲线图/折线图/柱状图参考:
    https://blog.csdn.net/sxt_zls/article/details/89419092
    https://www.codercto.com/a/45868.html
    https://zhuanlan.zhihu.com/p/48207046
    https://blog.csdn.net/qq_17766199/article/details/95632571?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-2-95632571.nonecase&utm_term=flutter%20%E5%8A%A8%E6%80%81%E7%BB%98%E5%88%B6%E6%9B%B2%E7%BA%BF

    相关文章

      网友评论

          本文标题:flutter贝塞尔曲线

          本文链接:https://www.haomeiwen.com/subject/donmsktx.html