Commits

Barry Schwartz committed c74f608

A bunch of code mostly for making it easier mix 2geom with OCaml.

  • Participants
  • Parent commits 769b1de

Comments (0)

Files changed (4)

File caml2geom.ml

   external sub_from : t -> t -> unit = "point_sub_from_wrapper"
   external mul_by : t -> Coord.t -> unit = "point_mul_by_wrapper"
   external div_by : t -> Coord.t -> unit = "point_div_by_wrapper"
+
+  let of_tuple (x,y) = make x y
+  let to_tuple p = (coord p 0, coord p 1)
 end
 
 module Interval =
   external at0 : t -> Coord.t = "bezier_at0_wrapper"
   external at1 : t -> Coord.t = "bezier_at1_wrapper"
   external value_at : t -> float -> Coord.t = "bezier_value_at_wrapper"
+
+  let of_2tuple (a,b) = make_order1 a b
+  let of_3tuple (a,b,c) = make_order2 a b c
+  let of_4tuple (a,b,c,d) = make_order3 a b c d
 end
 
 module Bezier_as_fragment : Fragment = Bezier
   external of_two_points : Point.t -> Point.t -> t = "bezier_curve_of_two_points_wrapper"
   external of_three_points : Point.t -> Point.t -> Point.t -> t = "bezier_curve_of_three_points_wrapper"
   external of_four_points : Point.t -> Point.t -> Point.t -> Point.t -> t = "bezier_curve_of_four_points_wrapper"
+  external order : t -> int = "bezier_curve_order_wrapper"
   external initial_point : t -> Point.t = "bezier_curve_initial_point_wrapper"
   external final_point : t -> Point.t = "bezier_curve_final_point_wrapper"
   external is_degenerate : t -> bool = "bezier_curve_is_degenerate_wrapper"
   external _unit_tangent_at : t -> Coord.t -> int -> Point.t = "bezier_curve_unit_tangent_at_wrapper"
   external _default_unit_tangent_at : t -> Coord.t -> Point.t = "bezier_curve_default_unit_tangent_at_wrapper"
   let unit_tangent_at = general_unit_tangent_at _default_unit_tangent_at _unit_tangent_at reverse
+
+  let of_array points = 
+    match points with
+      | [| p0; p1 |] -> of_two_points p0 p1
+      | [| p0; p1; p2 |] -> of_three_points p0 p1 p2
+      | [| p0; p1; p2; p3 |] -> of_four_points p0 p1 p2 p3
+      | _ -> invalid_arg "array length must be 2, 3, or 4"
+  external to_array : t -> Point.t array = "bezier_curve_points_wrapper"
+  let of_tuple_array tuples = of_array (Array.map Point.of_tuple tuples)
+  let to_tuple_array bc = Array.map Point.to_tuple (to_array bc)
 end
 
 module Line_segment =
 struct
   type t
   external to_curve : t -> Curve.t = "%identity"
+  external to_bezier_curve : t -> Bezier_curve.t = "%identity"
+  external of_two_points : Point.t -> Point.t -> t = "line_segment_of_two_points_wrapper"
+  external order : t -> int = "line_segment_order_wrapper"
   external initial_point : t -> Point.t = "line_segment_initial_point_wrapper"
   external final_point : t -> Point.t = "line_segment_final_point_wrapper"
   external is_degenerate : t -> bool = "line_segment_is_degenerate_wrapper"
   external _unit_tangent_at : t -> Coord.t -> int -> Point.t = "line_segment_unit_tangent_at_wrapper"
   external _default_unit_tangent_at : t -> Coord.t -> Point.t = "line_segment_default_unit_tangent_at_wrapper"
   let unit_tangent_at = general_unit_tangent_at _default_unit_tangent_at _unit_tangent_at reverse
+
+  let of_array points = 
+    match points with
+      | [| p0; p1 |] -> of_two_points p0 p1
+      | _ -> invalid_arg "array length must be 2"
+  external to_array : t -> Point.t array = "line_segment_points_wrapper"
+  let of_tuple_array tuples = of_array (Array.map Point.of_tuple tuples)
+  let to_tuple_array bc = Array.map Point.to_tuple (to_array bc)
 end
 
 module Quadratic_bezier =
 struct
   type t
   external to_curve : t -> Curve.t = "%identity"
+  external to_bezier_curve : t -> Bezier_curve.t = "%identity"
+  external of_three_points : Point.t -> Point.t -> Point.t -> t = "quadratic_bezier_of_three_points_wrapper"
+  external order : t -> int = "quadratic_bezier_order_wrapper"
   external initial_point : t -> Point.t = "quadratic_bezier_initial_point_wrapper"
   external final_point : t -> Point.t = "quadratic_bezier_final_point_wrapper"
   external is_degenerate : t -> bool = "quadratic_bezier_is_degenerate_wrapper"
   external _unit_tangent_at : t -> Coord.t -> int -> Point.t = "line_segment_unit_tangent_at_wrapper"
   external _default_unit_tangent_at : t -> Coord.t -> Point.t = "line_segment_default_unit_tangent_at_wrapper"
   let unit_tangent_at = general_unit_tangent_at _default_unit_tangent_at _unit_tangent_at reverse
+
+  let of_array points = 
+    match points with
+      | [| p0; p1; p2 |] -> of_three_points p0 p1 p2
+      | _ -> invalid_arg "array length must be 3"
+  external to_array : t -> Point.t array = "quadratic_bezier_points_wrapper"
+  let of_tuple_array tuples = of_array (Array.map Point.of_tuple tuples)
+  let to_tuple_array bc = Array.map Point.to_tuple (to_array bc)
 end
 
 module Cubic_bezier =
 struct
   type t
   external to_curve : t -> Curve.t = "%identity"
+  external to_bezier_curve : t -> Bezier_curve.t = "%identity"
+  external of_four_points : Point.t -> Point.t -> Point.t -> Point.t -> t = "cubic_bezier_of_four_points_wrapper"
+  external order : t -> int = "cubic_bezier_order_wrapper"
   external initial_point : t -> Point.t = "cubic_bezier_initial_point_wrapper"
   external final_point : t -> Point.t = "cubic_bezier_final_point_wrapper"
   external is_degenerate : t -> bool = "cubic_bezier_is_degenerate_wrapper"
   external _unit_tangent_at : t -> Coord.t -> int -> Point.t = "line_segment_unit_tangent_at_wrapper"
   external _default_unit_tangent_at : t -> Coord.t -> Point.t = "line_segment_default_unit_tangent_at_wrapper"
   let unit_tangent_at = general_unit_tangent_at _default_unit_tangent_at _unit_tangent_at reverse
+
+  let of_array points = 
+    match points with
+      | [| p0; p1; p2; p3 |] -> of_four_points p0 p1 p2 p3
+      | _ -> invalid_arg "array length must be 4"
+  external to_array : t -> Point.t array = "cubic_bezier_points_wrapper"
+  let of_tuple_array tuples = of_array (Array.map Point.of_tuple tuples)
+  let to_tuple_array bc = Array.map Point.to_tuple (to_array bc)
 end
 
 module type Path_type =
 sig
   type t
-
-  module type ClosingSegment =
-  sig
-  end
-
   type stitching = NO_STITCHING | STITCH_DISCONTINUOUS
-  module type StitchSegment =
-  sig
-  end
-
   external default : unit -> t = "new_default_path_wrapper"
   external make : Point.t -> t = "new_path_wrapper"
   external point_at : t -> float -> Point.t = "path_point_at_wrapper"
   external reverse : t -> t = "path_reverse_wrapper"
   external append_curve : ?stitch:stitching -> t -> Curve.t -> unit = "path_append_curve_wrapper"
   external append : ?stitch:stitching -> t -> t -> unit = "path_append_wrapper"
+  external nearest_point : ?from_t:float -> ?to_t:float -> t -> Point.t -> float * float = "path_nearest_point_wrapper"
+  external size_open : t -> int = "path_size_open_wrapper"
+  external size_closed : t -> int = "path_size_closed_wrapper"
+  external size_default : t -> int = "path_size_default_wrapper"
+  external size : t -> int = "path_size_wrapper"
+  external max_size : t -> int = "path_max_size_wrapper"
+  external empty : t -> bool = "path_empty_wrapper"
+  external closed : t -> bool = "path_closed_wrapper"
+  external close : t -> bool -> unit = "path_close_wrapper"
+  external to_cubic_beziers : t -> float -> Cubic_bezier.t list = "path_to_cubic_bezier_curves_wrapper"
 end
 
 module Path : Path_type =
 struct
   type t
-
-  module type ClosingSegment =
-  sig
-  end
-
   type stitching = NO_STITCHING | STITCH_DISCONTINUOUS
-  module type StitchSegment =
-  sig
-  end
-
   external default : unit -> t = "new_default_path_wrapper"
   external make : Point.t -> t = "new_path_wrapper"
   external point_at : t -> float -> Point.t = "path_point_at_wrapper"
   external reverse : t -> t = "path_reverse_wrapper"
   external append_curve : ?stitch:stitching -> t -> Curve.t -> unit = "path_append_curve_wrapper"
   external append : ?stitch:stitching -> t -> t -> unit = "path_append_wrapper"
+  external nearest_point : ?from_t:float -> ?to_t:float -> t -> Point.t -> float * float = "path_nearest_point_wrapper"
+  external size_open : t -> int = "path_size_open_wrapper"
+  external size_closed : t -> int = "path_size_closed_wrapper"
+  external size_default : t -> int = "path_size_default_wrapper"
+  external size : t -> int = "path_size_wrapper"
+  external max_size : t -> int = "path_max_size_wrapper"
+  external empty : t -> bool = "path_empty_wrapper"
+  external closed : t -> bool = "path_closed_wrapper"
+  external close : t -> bool -> unit = "path_close_wrapper"
+  external to_cubic_beziers : t -> float -> Cubic_bezier.t list = "path_to_cubic_bezier_curves_wrapper"
 end

File caml2geom.mli

   external sub_from : t -> t -> unit = "point_sub_from_wrapper"
   external mul_by : t -> Coord.t -> unit = "point_mul_by_wrapper"
   external div_by : t -> Coord.t -> unit = "point_div_by_wrapper"
+
+  val of_tuple : Coord.t * Coord.t -> t
+  val to_tuple : t -> Coord.t * Coord.t
 end
 
 module Interval :
   external at0 : t -> Coord.t = "bezier_at0_wrapper"
   external at1 : t -> Coord.t = "bezier_at1_wrapper"
   external value_at : t -> float -> Coord.t = "bezier_value_at_wrapper"
+
+  val of_2tuple : Coord.t * Coord.t -> t
+  val of_3tuple : Coord.t * Coord.t * Coord.t -> t
+  val of_4tuple : Coord.t * Coord.t * Coord.t * Coord.t -> t
 end
 
 module Bezier_as_fragment : Fragment
   external of_two_points : Point.t -> Point.t -> t = "bezier_curve_of_two_points_wrapper"
   external of_three_points : Point.t -> Point.t -> Point.t -> t = "bezier_curve_of_three_points_wrapper"
   external of_four_points : Point.t -> Point.t -> Point.t -> Point.t -> t = "bezier_curve_of_four_points_wrapper"
+  external order : t -> int = "bezier_curve_order_wrapper"
   external initial_point : t -> Point.t = "bezier_curve_initial_point_wrapper"
   external final_point : t -> Point.t = "bezier_curve_final_point_wrapper"
   external is_degenerate : t -> bool = "bezier_curve_is_degenerate_wrapper"
   external winding : t -> Point.t -> int = "bezier_curve_winding_wrapper"
   val unit_tangent_at : ?num_derivs:int -> t -> Coord.t -> Point.t
   external degrees_of_freedom : t -> int = "bezier_curve_degrees_of_freedom_wrapper"
+
+  val of_array : Point.t array -> t
+  external to_array : t -> Point.t array = "bezier_curve_points_wrapper"
+  val of_tuple_array : (Coord.t * Coord.t) array -> t
+  val to_tuple_array : t -> (Coord.t * Coord.t) array
 end
 
 module Line_segment :
 sig
   type t
   external to_curve : t -> Curve.t = "%identity"
+  external to_bezier_curve : t -> Bezier_curve.t = "%identity"
+  external of_two_points : Point.t -> Point.t -> t = "line_segment_of_two_points_wrapper"
+  external order : t -> int = "line_segment_order_wrapper"
   external initial_point : t -> Point.t = "line_segment_initial_point_wrapper"
   external final_point : t -> Point.t = "line_segment_final_point_wrapper"
   external is_degenerate : t -> bool = "line_segment_is_degenerate_wrapper"
   external winding : t -> Point.t -> int = "line_segment_winding_wrapper"
   val unit_tangent_at : ?num_derivs:int -> t -> Coord.t -> Point.t
   external degrees_of_freedom : t -> int = "line_segment_degrees_of_freedom_wrapper"
+
+  val of_array : Point.t array -> t
+  external to_array : t -> Point.t array = "line_segment_points_wrapper"
+  val of_tuple_array : (Coord.t * Coord.t) array -> t
+  val to_tuple_array : t -> (Coord.t * Coord.t) array
 end
 
 module Quadratic_bezier :
 sig
   type t
   external to_curve : t -> Curve.t = "%identity"
+  external to_bezier_curve : t -> Bezier_curve.t = "%identity"
+  external of_three_points : Point.t -> Point.t -> Point.t -> t = "quadratic_bezier_of_three_points_wrapper"
+  external order : t -> int = "quadratic_bezier_order_wrapper"
   external initial_point : t -> Point.t = "quadratic_bezier_initial_point_wrapper"
   external final_point : t -> Point.t = "quadratic_bezier_final_point_wrapper"
   external is_degenerate : t -> bool = "quadratic_bezier_is_degenerate_wrapper"
   external winding : t -> Point.t -> int = "quadratic_bezier_winding_wrapper"
   val unit_tangent_at : ?num_derivs:int -> t -> Coord.t -> Point.t
   external degrees_of_freedom : t -> int = "quadratic_bezier_degrees_of_freedom_wrapper"
+
+  val of_array : Point.t array -> t
+  external to_array : t -> Point.t array = "quadratic_bezier_points_wrapper"
+  val of_tuple_array : (Coord.t * Coord.t) array -> t
+  val to_tuple_array : t -> (Coord.t * Coord.t) array
 end
 
 module Cubic_bezier :
 sig
   type t
   external to_curve : t -> Curve.t = "%identity"
+  external to_bezier_curve : t -> Bezier_curve.t = "%identity"
+  external of_four_points : Point.t -> Point.t -> Point.t -> Point.t -> t = "cubic_bezier_of_four_points_wrapper"
+  external order : t -> int = "cubic_bezier_order_wrapper"
   external initial_point : t -> Point.t = "cubic_bezier_initial_point_wrapper"
   external final_point : t -> Point.t = "cubic_bezier_final_point_wrapper"
   external is_degenerate : t -> bool = "cubic_bezier_is_degenerate_wrapper"
   external winding : t -> Point.t -> int = "cubic_bezier_winding_wrapper"
   val unit_tangent_at : ?num_derivs:int -> t -> Coord.t -> Point.t
   external degrees_of_freedom : t -> int = "cubic_bezier_degrees_of_freedom_wrapper"
+
+  val of_array : Point.t array -> t
+  external to_array : t -> Point.t array = "cubic_bezier_points_wrapper"
+  val of_tuple_array : (Coord.t * Coord.t) array -> t
+  val to_tuple_array : t -> (Coord.t * Coord.t) array
 end
 
 module type Path_type =
 sig
   type t
-
-  module type ClosingSegment =
-  sig
-  end
-
   type stitching = NO_STITCHING | STITCH_DISCONTINUOUS
-  module type StitchSegment =
-  sig
-  end
-
   external default : unit -> t = "new_default_path_wrapper"
   external make : Point.t -> t = "new_path_wrapper"
   external point_at : t -> float -> Point.t = "path_point_at_wrapper"
   external reverse : t -> t = "path_reverse_wrapper"
   external append_curve : ?stitch:stitching -> t -> Curve.t -> unit = "path_append_curve_wrapper"
   external append : ?stitch:stitching -> t -> t -> unit = "path_append_wrapper"
+  external nearest_point : ?from_t:float -> ?to_t:float -> t -> Point.t -> float * float = "path_nearest_point_wrapper"
+  external size_open : t -> int = "path_size_open_wrapper"
+  external size_closed : t -> int = "path_size_closed_wrapper"
+  external size_default : t -> int = "path_size_default_wrapper"
+  external size : t -> int = "path_size_wrapper"
+  external max_size : t -> int = "path_max_size_wrapper"
+  external empty : t -> bool = "path_empty_wrapper"
+  external closed : t -> bool = "path_closed_wrapper"
+  external close : t -> bool -> unit = "path_close_wrapper"
+  external to_cubic_beziers : t -> float -> Cubic_bezier.t list = "path_to_cubic_bezier_curves_wrapper"
 end
 
 module Path : Path_type

File caml2geom_stubs.c

 #include <2geom/path.h>
 #include <2geom/point.h>
 #include <2geom/rect.h>
+#include <2geom/sbasis-to-bezier.h>
 #include <2geom/transforms.h>
 
 extern "C" {
 
 //-------------------------------------------------------------------------
 
-#define fragment_getval_wrapper(t, name, func, typeconv)                \
+#define getval_wrapper(t, name, func, typeconv)                         \
     extern "C" CAMLprim value name(value _v)                            \
     {                                                                   \
         CAMLparam1(_v);                                                 \
         CAMLreturn(typeconv(OPAQUE_P(t, _v)->func()));                  \
     }
 
+#define setval_wrapper(t, name, func, typeconv)                         \
+    extern "C" CAMLprim value name(value _v, value _setting)            \
+    {                                                                   \
+        CAMLparam2(_v, _setting);                                       \
+        OPAQUE_P(t, _v)->func(typeconv(_setting));                      \
+        CAMLreturn(Val_unit);                                           \
+    }
+
+//-------------------------------------------------------------------------
+
 #define fragment_wrappers(t, name)                                      \
                                                                         \
     extern "C" CAMLprim value new_default_##name##_wrapper(void)        \
         CAMLreturn(_v);                                                 \
     }                                                                   \
                                                                         \
-    fragment_getval_wrapper(t, name##_is_zero_wrapper, isZero, Val_bool); \
-    fragment_getval_wrapper(t, name##_is_constant_wrapper, isConstant, Val_bool); \
-    fragment_getval_wrapper(t, name##_is_finite_wrapper, isFinite, Val_bool); \
-    fragment_getval_wrapper(t, name##_at0_wrapper, at0, caml_copy_double); \
-    fragment_getval_wrapper(t, name##_at1_wrapper, at1, caml_copy_double); \
+    getval_wrapper(t, name##_is_zero_wrapper, isZero, Val_bool);        \
+    getval_wrapper(t, name##_is_constant_wrapper, isConstant, Val_bool); \
+    getval_wrapper(t, name##_is_finite_wrapper, isFinite, Val_bool);    \
+    getval_wrapper(t, name##_at0_wrapper, at0, caml_copy_double);       \
+    getval_wrapper(t, name##_at1_wrapper, at1, caml_copy_double);       \
                                                                         \
     extern "C" CAMLprim value name##_value_at_wrapper(value _v, value _s) \
     {                                                                   \
         CAMLreturn(Val_int(curve->degreesOfFreedom()));                 \
     }
 
+#define bezier_curve_wrappers(t, name)                                  \
+                                                                        \
+    curve_wrappers(t, name);                                            \
+    getval_wrapper(t, name##_order_wrapper, order, Val_int);            \
+                                                                        \
+    extern "C" CAMLprim value name##_points_wrapper(value _bezcurve)    \
+    {                                                                   \
+        CAMLparam1(_bezcurve);                                          \
+        CAMLlocal2(_point, _result);                                    \
+        t *bc = OPAQUE_P(t, _bezcurve);                                 \
+        std::vector<Geom::Point> points = bc->points();                 \
+        int n = points.size();                                          \
+        _result = caml_alloc(n, 0);                                     \
+        for (int i = 0; i < n; i++) {                                   \
+            _point = OPAQUE_P_ALLOC(Geom::Point, point_ops);            \
+            OPAQUE_P(Geom::Point, _point) = new Geom::Point(points[i]); \
+            Store_field(_result, i, _point);                            \
+        }                                                               \
+        CAMLreturn(_result);                                            \
+    }
+
 //-------------------------------------------------------------------------
 
 extern "C" CAMLprim value epsilon_wrapper(void)
 
 //-------------------------------------------------------------------------
 
-curve_wrappers(Geom::BezierCurve, bezier_curve);
+bezier_curve_wrappers(Geom::BezierCurve, bezier_curve);
 
 extern "C" CAMLprim value bezier_curve_of_two_beziers_wrapper(value _bez0, value _bez1)
 {
 
 //-------------------------------------------------------------------------
 
-curve_wrappers(Geom::LineSegment, line_segment);
-curve_wrappers(Geom::QuadraticBezier, quadratic_bezier);
-curve_wrappers(Geom::CubicBezier, cubic_bezier);
+bezier_curve_wrappers(Geom::LineSegment, line_segment);
+bezier_curve_wrappers(Geom::QuadraticBezier, quadratic_bezier);
+bezier_curve_wrappers(Geom::CubicBezier, cubic_bezier);
+
+extern "C" CAMLprim value line_segment_of_two_points_wrapper(value _p0, value _p1)
+{
+    CAMLparam2(_p0, _p1);
+    CAMLlocal1(_bezcurve);
+    Geom::LineSegment *bc = new Geom::LineSegment(*OPAQUE_P(Geom::Point, _p0),
+                                                  *OPAQUE_P(Geom::Point, _p1));
+    _bezcurve = OPAQUE_P_ALLOC(Geom::LineSegment, line_segment_ops);
+    OPAQUE_P(Geom::LineSegment, _bezcurve) = bc;
+    CAMLreturn(_bezcurve);
+}
+
+extern "C" CAMLprim value quadratic_bezier_of_three_points_wrapper(value _p0, value _p1, value _p2)
+{
+    CAMLparam3(_p0, _p1, _p2);
+    CAMLlocal1(_bezcurve);
+    Geom::QuadraticBezier *bc = new Geom::QuadraticBezier(*OPAQUE_P(Geom::Point, _p0),
+                                                          *OPAQUE_P(Geom::Point, _p1),
+                                                          *OPAQUE_P(Geom::Point, _p2));
+    _bezcurve = OPAQUE_P_ALLOC(Geom::QuadraticBezier, quadratic_bezier_ops);
+    OPAQUE_P(Geom::QuadraticBezier, _bezcurve) = bc;
+    CAMLreturn(_bezcurve);
+}
+
+extern "C" CAMLprim value cubic_bezier_of_four_points_wrapper(value _p0, value _p1, value _p2, value _p3)
+{
+    CAMLparam4(_p0, _p1, _p2, _p3);
+    CAMLlocal1(_bezcurve);
+    Geom::CubicBezier *bc = new Geom::CubicBezier(*OPAQUE_P(Geom::Point, _p0),
+                                                  *OPAQUE_P(Geom::Point, _p1),
+                                                  *OPAQUE_P(Geom::Point, _p2),
+                                                  *OPAQUE_P(Geom::Point, _p3));
+    _bezcurve = OPAQUE_P_ALLOC(Geom::CubicBezier, cubic_bezier_ops);
+    OPAQUE_P(Geom::CubicBezier, _bezcurve) = bc;
+    CAMLreturn(_bezcurve);
+}
 
 //-------------------------------------------------------------------------
 
     CAMLreturn(Val_unit);
 }
 
+extern "C" CAMLprim value path_nearest_point_wrapper(value _from_t, value _to_t, value _path, value _point)
+{
+    CAMLparam4(_from_t, _to_t, _path, _point);
+    CAMLlocal1(_result);
+    Geom::Path *path = OPAQUE_P(Geom::Path, _path);
+    Geom::Point *point = OPAQUE_P(Geom::Point, _point);
+    double from_t = _from_t == Val_int(0) ? 0 : Double_val(Field(_from_t, 0));
+    double to_t = _to_t == Val_int(0) ? path->size_default() : Double_val(Field(_to_t, 0));
+    double time;
+    double distance_squared;
+    try {
+        time = path->nearestPoint(*point, from_t, to_t, &distance_squared);
+    }
+    catch (Geom::RangeError&) {
+        caml_invalid_argument("[from,to] interval out of bounds");
+    }
+    _result = caml_alloc(2, 0);
+    Store_field(_result, 0, caml_copy_double(time));
+    Store_field(_result, 1, caml_copy_double(distance_squared));
+    CAMLreturn(_result);
+}
+
+getval_wrapper(Geom::Path, path_size_open_wrapper, size_open, Val_int);
+getval_wrapper(Geom::Path, path_size_closed_wrapper, size_closed, Val_int);
+getval_wrapper(Geom::Path, path_size_default_wrapper, size_default, Val_int);
+getval_wrapper(Geom::Path, path_size_wrapper, size, Val_int);
+getval_wrapper(Geom::Path, path_max_size_wrapper, max_size, Val_int);
+
+getval_wrapper(Geom::Path, path_empty_wrapper, empty, Val_bool);
+getval_wrapper(Geom::Path, path_closed_wrapper, closed, Val_bool);
+setval_wrapper(Geom::Path, path_close_wrapper, close, Bool_val);
+
+extern "C" CAMLprim value path_to_cubic_bezier_curves_wrapper(value _path, value _tol)
+{
+    CAMLparam2(_path, _tol);
+    CAMLlocal3(_list, _node, _curve);
+    Geom::Path *path = OPAQUE_P(Geom::Path, _path);
+    Geom::Piecewise<Geom::D2<Geom::SBasis> > sb = path->toPwSb();
+    std::vector<Geom::Path> cubic_paths = path_from_piecewise(sb, Double_val(_tol), true);
+    _list = Val_emptylist;
+    for (int i = (int)cubic_paths.size() - 1; 0 <= i; i--) {
+        Geom::Path *p = &cubic_paths[i];
+        for (Geom::Path::const_iterator j = p->end_default(); j != p->begin(); j--) {
+            Geom::Path::const_iterator k = j;
+            k--;
+            Geom::BezierCurve *curve = dynamic_cast<Geom::BezierCurve*>(k->duplicate());
+            _curve = OPAQUE_P_ALLOC(Geom::BezierCurve, cubic_bezier_ops);
+            OPAQUE_P(Geom::BezierCurve, _curve) = curve;
+            _node = caml_alloc(2, 0);
+            Store_field(_node, 0, _curve);
+            Store_field(_node, 1, _list);
+            _list = _node;
+        }
+    }
+    CAMLreturn(_list);
+}
+
 //-------------------------------------------------------------------------
 let _ = printf "path5 point_at 4.5 = (%f,%f)\n"
   (Point.coord (Path.point_at path5 4.5) 0)
   (Point.coord (Path.point_at path5 4.5) 1) ;;
+let _ = printf "path1 empty = %B\n" (Path.empty path1) ;;
+let _ = printf "path5 empty = %B\n" (Path.empty path5) ;;
+let _ = printf "path1 closed = %B\n" (Path.closed path1) ;;
+let _ = printf "path5 closed = %B\n" (Path.closed path5) ;;
+Path.close path5 true ;;
+let _ = printf "path5 closed = %B\n" (Path.closed path5) ;;
+let _ = printf "path5 size_open = %d\n" (Path.size_open path5) ;;
+let _ = printf "path5 size_closed = %d\n" (Path.size_closed path5) ;;
+let _ = printf "path5 size_default = %d\n" (Path.size_default path5) ;;
+let _ = printf "path5 size = %d\n" (Path.size path5) ;;
+let _ = printf "path5 max_size = %d\n" (Path.max_size path5) ;;
+let (t,d_squared) = Path.nearest_point path5 (Point.make 0. 0.) ;;
+let _ = printf "path5 nearest_point to (0.,0.) = %f %f\n" t d_squared ;;
+let (t,d_squared) = Path.nearest_point path5 (Point.make 100. 100.) ;;
+let _ = printf "path5 nearest_point to (100.,100.) = %f %f\n" t d_squared ;;
+let (t,d_squared) = Path.nearest_point ~from_t:0.4 ~to_t:0.9 (Path.portion path5 0.5 0.9) (Point.make 0. 0.) ;;
+let _ = printf "path5 portion nearest_point to (0.,0.) = %f %f\n" t d_squared ;;
+let (t,d_squared) = Path.nearest_point ~from_t:0.4 ~to_t:0.9 path5 (Point.make 0. 0.) ;;
+let _ = printf "path5 nearest_point to (0.,0.) = %f %f\n" t d_squared ;;
+let (t,d_squared) = Path.nearest_point ~from_t:2.4 ~to_t:2.9 path5 (Point.make 0. 0.) ;;
+let _ = printf "path5 nearest_point to (0.,0.) = %f %f\n" t d_squared ;;
+let (t,d_squared) = Path.nearest_point ~from_t:0.4 ~to_t:0.9 path5 (Point.make 100. 100.) ;;
+let _ = printf "path5 nearest_point to (100.,100.) = %f %f\n" t d_squared ;;
+let bc_a = Bezier_curve.of_tuple_array [|(1.,2.);(10.,5.);(50.,2.)|] ;;
+let t_a = Bezier_curve.to_tuple_array bc_a ;;
+print_string "[|"; Array.iter (fun (x,y) -> printf "(%f,%f);" x y) t_a; print_endline "|]" ;;
+let _ = printf "bc_a order = %d\n" (Bezier_curve.order bc_a) ;;
+let path_a = Path.make (Point.make 1. 2.) ;;
+Path.append_curve path_a (Bezier_curve.to_curve bc_a) ;;
+let (t,d_squared) = Path.nearest_point ~from_t:0.4 ~to_t:0.9 path_a (Point.make 0. 0.) ;;
+let _ = printf "path_a nearest_point to (0.,0.) = %f %f\n" t d_squared ;;
+
+let beziers = Path.to_cubic_beziers path5 0.001 ;;
+List.iter
+  (fun bez ->
+    let tuples = Cubic_bezier.to_tuple_array bez in
+    print_string "[|";
+    Array.iter (fun (x,y) -> printf "(%f,%f);" x y) tuples;
+    print_endline "|]")
+beziers ;;
 
 (*-----------------------------------------------------------------------*)