From 986a36b3728eba40789d6063997dafda67b519ec Mon Sep 17 00:00:00 2001 From: Sébastien Dailly Date: Sun, 20 Dec 2020 06:38:04 +0100 Subject: Update --- path/builder.ml | 188 +++++++++++++++++++++++++++++++------------------------- 1 file changed, 103 insertions(+), 85 deletions(-) (limited to 'path/builder.ml') diff --git a/path/builder.ml b/path/builder.ml index 01dfb35..2774cae 100755 --- a/path/builder.ml +++ b/path/builder.ml @@ -10,6 +10,11 @@ module type P = sig val copy : t -> Gg.v2 -> t +end + +module type REPR = sig + type t + type 'a repr val create_path @@ -23,7 +28,7 @@ module type P = sig : t -> 'a repr -> 'a repr val quadratic_to - : t -> t -> t -> t -> 'a repr -> 'a repr + : t -> Gg.v2 -> Gg.v2 -> t -> 'a repr -> 'a repr val stop : 'a repr -> 'a repr @@ -34,8 +39,8 @@ module Make(Point:P) = struct (** Point creation **) type bezier = - { p0:Point.t (* The starting point *) - ; p1:Point.t (* The end point *) + { p0:Point.t (* The starting point *) + ; p1:Point.t (* The end point *) ; ctrl0:Gg.v2 (* The control point *) ; ctrl1:Gg.v2 } (* The control point *) @@ -169,91 +174,104 @@ module Make(Point:P) = struct curves - (** Drawing path **) - - let draw - : t -> 'a Point.repr - = fun (points, beziers) -> - - let path = Point.create_path () in - let path = match points with - | [] -> - ( path ) - | p1::[] -> - ( Point.start p1 path ) - | p1::p2::[] -> - let path = - Point.start p1 path - |> Point.line_to p2 in - ( path ) - | p0::p1::p2::[] -> - let path = Point.start p0 path in - - let b = Shapes.Bezier.three_points_quadratic - (Point.get_coord p0) - (Point.get_coord p1) - (Point.get_coord p2) - |> Shapes.Bezier.quadratic_to_cubic in - - let p0' = Point.copy p0 b.Shapes.Bezier.p0 - and ctrl0 = Point.copy p0 b.Shapes.Bezier.ctrl0 - and ctrl1 = Point.copy p1 b.Shapes.Bezier.ctrl1 - and p2' = Point.copy p1 b.Shapes.Bezier.p1 in - - ( Point.quadratic_to p0' ctrl0 ctrl1 p2' path ) - | (p0::_ as points) -> - - let (let*) v f = - match v with - | Ok beziers -> f beziers - | _ -> path in - - let points' = List.map ~f:Point.get_coord points in - let connexion = match beziers with - | [] -> None - | hd ::_ -> Some (Point.get_coord hd.p1) in - - let* beziers = Shapes.Bspline.to_bezier ?connexion1:connexion points' in - - (* Stdlib does not provide fold_left_i function and we need to map - each bezier point with the associated point in the curve. - - So I use references here for keeping each result element - - *) - let path = ref path in - let point = ref p0 in - - List.iteri - points - ~f:(fun i pt -> - - (* The first iteration is ignored, as we need both previous and - current point for the two point in the curve *) - if i > 0 then ( - - let bezier = Array.get beziers (i - 1) in - let p0' = !point - and ctrl0 = Point.copy (!point) bezier.Shapes.Bezier.ctrl0 - and ctrl1 = Point.copy pt bezier.Shapes.Bezier.ctrl1 - and p1' = pt in - - path := Point.quadratic_to p0' ctrl0 ctrl1 p1' (!path); - - point := pt; - ) - ); - ( !path ) - in - - let path = List.fold_left beziers + module Draw(Repr:REPR with type t = Point.t) = struct + + (** Drawing path **) + + let draw + : t -> 'a Repr.repr + = fun (points, beziers) -> + + let path = Repr.create_path () in + + (* Represent the last points *) + let path = match points with + | [] -> + ( path ) + | p1::[] -> + ( Repr.start p1 path ) + | p1::p2::[] -> + let path = + Repr.start p1 path + |> Repr.line_to p2 in + ( path ) + | p0::p1::p2::[] -> + let path = Repr.start p0 path in + + let b = Shapes.Bezier.quadratic_to_cubic + @@ Shapes.Bezier.three_points_quadratic + (Point.get_coord p0) + (Point.get_coord p1) + (Point.get_coord p2) + in + + let p0' = Point.copy p0 b.Shapes.Bezier.p0 + and p2' = Point.copy p1 b.Shapes.Bezier.p1 in + + ( Repr.quadratic_to + p0' + b.Shapes.Bezier.ctrl0 + b.Shapes.Bezier.ctrl1 + p2' + path ) + | (p0::_ as points) -> + + let (let*) v f = + match v with + | Ok beziers -> f beziers + | _ -> path in + + let points' = List.map ~f:Point.get_coord points in + let connexion = match beziers with + | [] -> None + | hd ::_ -> Some (Point.get_coord hd.p1) in + + let* beziers = Shapes.Bspline.to_bezier ?connexion1:connexion points' in + + (* Stdlib does not provide fold_left_i function and we need to map + each bezier point with the associated point in the curve. + + So I use references here for keeping each result element + + *) + let path = ref path in + let point = ref p0 in + + List.iteri + points + ~f:(fun i pt -> + + (* The first iteration is ignored, as we need both previous and + current point for the two point in the curve. + + Do not forget that there is always n-1 bezier curve for n + points *) + if i > 0 then ( + + let bezier = Array.get beziers (i - 1) in + + path := Repr.quadratic_to + !point + bezier.Shapes.Bezier.ctrl0 + bezier.Shapes.Bezier.ctrl1 + pt + (!path); + point := pt; + ) + ); + ( !path ) + in + + (* Now represent the already evaluated points. Much easer to do, just + iterate on them *) + Repr.stop @@ List.fold_left beziers ~init:path ~f:(fun path bezier -> let p0' = bezier.p0 - and ctrl0 = Point.copy bezier.p0 bezier.ctrl0 - and ctrl1 = Point.copy bezier.p1 bezier.ctrl1 + and ctrl0 = bezier.ctrl0 + and ctrl1 = bezier.ctrl1 and p1' = bezier.p1 in - Point.quadratic_to p0' ctrl0 ctrl1 p1' path + Repr.quadratic_to p0' ctrl0 ctrl1 p1' path ) - in Point.stop path + end end -- cgit v1.2.3