diff options
author | Sébastien Dailly <sebastien@chimrod.com> | 2020-12-20 06:38:04 +0100 |
---|---|---|
committer | Sébastien Dailly <sebastien@chimrod.com> | 2020-12-20 06:38:04 +0100 |
commit | 986a36b3728eba40789d6063997dafda67b519ec (patch) | |
tree | f0c26704df237b5ccad380596c49a3b13eeac14f | |
parent | 01c0f5faf98b78d44aaae7f70e0cf4229ad8ed91 (diff) |
Update
-rwxr-xr-x | path/builder.ml | 188 | ||||
-rwxr-xr-x | path/builder.mli | 24 | ||||
-rwxr-xr-x | path/draw.ml | 1 | ||||
-rwxr-xr-x | path/point.ml | 74 | ||||
-rwxr-xr-x | path/point.mli | 21 | ||||
-rwxr-xr-x | path/wireFramePrinter.ml | 78 | ||||
-rwxr-xr-x | path/wireFramePrinter.mli | 23 | ||||
-rwxr-xr-x | script.ml | 3 |
8 files changed, 224 insertions, 188 deletions
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 diff --git a/path/builder.mli b/path/builder.mli index 64617fa..17c1a2a 100755 --- a/path/builder.mli +++ b/path/builder.mli @@ -6,9 +6,15 @@ module type P = sig val get_coord : t -> Gg.v2 + (** Copy a point and all thoses properties to the given location *) val copy : t -> Gg.v2 -> t - type 'a repr +end + +module type REPR = sig + type t + + type 'a repr val create_path : unit -> 'a repr @@ -21,18 +27,17 @@ 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 end - module Make(P:P) : sig type bezier = - { p0:P.t (* The starting point *) - ; p1:P.t (* The end point *) + { p0:P.t (* The starting point *) + ; p1:P.t (* The end point *) ; ctrl0:Gg.v2 (* The control point *) ; ctrl1:Gg.v2 } (* The control point *) @@ -62,6 +67,11 @@ module Make(P:P) : sig val points_to_beziers : P.t list -> Shapes.Bezier.t array -> bezier array - val draw - : t -> 'a P.repr + module Draw(Repr:REPR with type t = P.t) : sig + + (** Represent the the current path *) + val draw + : t -> 'a Repr.repr + end + end diff --git a/path/draw.ml b/path/draw.ml index b4b7e28..e628dbc 100755 --- a/path/draw.ml +++ b/path/draw.ml @@ -4,6 +4,7 @@ module Path = Brr_canvas.C2d.Path module Point = Point module Path_Builder = Builder.Make(Point) module Builder = Builder +module WireFrame = WireFramePrinter (* (** Translate the point in the canva area *) diff --git a/path/point.ml b/path/point.ml index 7a32ae1..83cb168 100755 --- a/path/point.ml +++ b/path/point.ml @@ -30,77 +30,3 @@ let get_coord' let open Gg.V2 in let trans = of_polar @@ v t.size t.angle in t.p + trans - -module Repr = CanvaPrinter - -type 'a repr = - { back: ('a Repr.t -> 'a Repr.t) - ; path: ('a Repr.t) - ; last_point : t option - } - -let create_path - : unit -> 'a repr - = fun () -> - { back = Repr.close - ; path = Repr.create () - ; last_point = None - } - -(* Start a new path. *) -let start - : t -> 'a repr -> 'a repr - = fun t {back; path; _} -> - let path = Repr.move_to (get_coord t) path in - let line' = Repr.line_to (get_coord' t) in - { back = (fun p -> back @@ line' p) - ; path - ; last_point = Some t - } - -let line_to - : t -> 'a repr -> 'a repr - = fun t {back; path; _} -> - let line' = Repr.line_to (get_coord' t) in - { back = (fun t -> back @@ line' t) - ; path = Repr.line_to t.p path - ; last_point = Some t - } - -let quadratic_to - : t -> t -> t -> t -> 'a repr -> 'a repr - = fun p0 ctrl0 ctrl1 p1 t -> - - let line' path = - Repr.quadratic_to - (get_coord' ctrl1) - (get_coord' ctrl0) - (get_coord' p0) path in - - let path = Repr.quadratic_to - (get_coord ctrl0) - (get_coord ctrl1) - (get_coord p1) - t.path in - { back = (fun p -> t.back @@ line' p) - ; path - ; last_point = Some p1 - } - -let stop - : 'a repr -> 'a repr - = fun {back; path; last_point} -> - - let path = - match last_point with - | Some point -> Repr.line_to (get_coord' point) path - | None -> path in - - { back = (fun x -> x) - ; path = back path - ; last_point = None } - -let get - : 'a repr -> 'a Repr.t - = fun {back; path; _} -> - back path diff --git a/path/point.mli b/path/point.mli index 6418de4..521eced 100755 --- a/path/point.mli +++ b/path/point.mli @@ -12,24 +12,3 @@ val copy : t -> Gg.v2 -> t val get_coord' : t -> Gg.v2 - -type 'a repr - -val create_path - : unit -> 'a repr - -(* Start a new path. *) -val start - : t -> 'a repr -> 'a repr - -val line_to - : t -> 'a repr -> 'a repr - -val quadratic_to - : t -> t -> t -> t -> 'a repr -> 'a repr - -val stop - : 'a repr -> 'a repr - -val get - : 'a repr -> 'a CanvaPrinter.t diff --git a/path/wireFramePrinter.ml b/path/wireFramePrinter.ml new file mode 100755 index 0000000..a0f52d6 --- /dev/null +++ b/path/wireFramePrinter.ml @@ -0,0 +1,78 @@ +module Repr = CanvaPrinter + +type t = Point.t + +type 'a repr = + { back: ('a Repr.t -> 'a Repr.t) + ; path: ('a Repr.t) + ; last_point : Point.t option + } + +let create_path + : unit -> 'a repr + = fun () -> + { back = Repr.close + ; path = Repr.create () + ; last_point = None + } + +(* Start a new path. *) +let start + : Point.t -> 'a repr -> 'a repr + = fun t {back; path; _} -> + let path = Repr.move_to (Point.get_coord t) path in + let line' = Repr.line_to (Point.get_coord' t) in + { back = (fun p -> back @@ line' p) + ; path + ; last_point = Some t + } + +let line_to + : Point.t -> 'a repr -> 'a repr + = fun t {back; path; _} -> + let line' = Repr.line_to (Point.get_coord' t) in + { back = (fun t -> back @@ line' t) + ; path = Repr.line_to (Point.get_coord t) path + ; last_point = Some t + } + +let quadratic_to + : Point.t -> Gg.v2 -> Gg.v2 -> Point.t -> 'a repr -> 'a repr + = fun p0 ctrl0 ctrl1 p1 t -> + + let ctrl0' = Point.copy p1 ctrl0 + and ctrl1' = Point.copy p1 ctrl1 in + + let line' path = + Repr.quadratic_to + (Point.get_coord' @@ ctrl1') + (Point.get_coord' ctrl0') + (Point.get_coord' p0) path in + + let path = Repr.quadratic_to + (Point.get_coord ctrl0') + (Point.get_coord ctrl1') + (Point.get_coord p1) + t.path in + { back = (fun p -> t.back @@ line' p) + ; path + ; last_point = Some p1 + } + +let stop + : 'a repr -> 'a repr + = fun {back; path; last_point} -> + + let path = + match last_point with + | Some point -> Repr.line_to (Point.get_coord' point) path + | None -> path in + + { back = (fun x -> x) + ; path = back path + ; last_point = None } + +let get + : 'a repr -> 'a Repr.t + = fun {back; path; _} -> + back path diff --git a/path/wireFramePrinter.mli b/path/wireFramePrinter.mli new file mode 100755 index 0000000..26974f5 --- /dev/null +++ b/path/wireFramePrinter.mli @@ -0,0 +1,23 @@ +type 'a repr + +type t = Point.t + +val create_path + : unit -> 'a repr + +(* Start a new path. *) +val start + : Point.t -> 'a repr -> 'a repr + +val line_to + : Point.t -> 'a repr -> 'a repr + +val quadratic_to + : Point.t -> Gg.v2 -> Gg.v2 -> Point.t -> 'a repr -> 'a repr + +val stop + : 'a repr -> 'a repr + +val get + : 'a repr -> 'a CanvaPrinter.t + @@ -8,6 +8,7 @@ module Point = Draw.Point module Path = Draw module Path_Builder = Path.Builder.Make(Point) +module Path_Printer = Path_Builder.Draw(Path.WireFrame) type mode = | Edit @@ -199,7 +200,7 @@ let on_change canva mouse_position state = state.current in - let path = Point.get @@ Path_Builder.draw current in + let path = Draw.WireFrame.get @@ Path_Printer.draw current in stroke context path; (* |