Commits

Barry Schwartz committed 325690c

Initial Bezier curve support. Largely this is a check-in to secure the way I am managing opaque C++ objects.

  • Participants
  • Parent commits b7c33ad

Comments (0)

Files changed (4)

File caml2geom.ml

 sig
   type t
   type output_type
+  val default : unit -> t
   val is_zero : t -> bool
   val is_constant : t -> bool
   val is_finite : t -> bool
 module Coord =
 struct
   type t = float
+  type dim2 = X | Y
   external _get_epsilon : unit -> t = "epsilon_wrapper"
   let _eps_value = _get_epsilon ()
   let epsilon = _eps_value
 module Point =
 struct
   type t
+  external default : unit -> t = "new_default_point_wrapper"
   external make : Coord.t -> Coord.t -> t = "new_point_wrapper"
   external copy : t -> t = "copy_point_wrapper"
   external coord : t -> int -> Coord.t = "point_coord_wrapper"
 struct
   type t
   type output_type = Coord.t
+  external default : unit -> t = "new_default_bezier_wrapper"
+  external make_order0 : Coord.t -> t = "new_bezier_order0_wrapper"
+  external make_order1 : Coord.t -> Coord.t -> t = "new_bezier_order1_wrapper"
+  external make_order2 : Coord.t -> Coord.t -> Coord.t -> t = "new_bezier_order2_wrapper"
   external make_order3 : Coord.t -> Coord.t -> Coord.t -> Coord.t -> t = "new_bezier_order3_wrapper"
   external is_zero : t -> bool = "bezier_is_zero_wrapper"
   external is_constant : t -> bool = "bezier_is_constant_wrapper"
   external value_at : t -> float -> Coord.t = "bezier_value_at_wrapper"
 end
 
-module Bezier_as_fragment = (Bezier : Fragment)
+module Bezier_as_fragment : Fragment = Bezier
+
+module type Curve =
+sig
+  type t
+  val initial_point : t -> Point.t
+  val final_point : t -> Point.t
+  val is_degenerate : t -> bool
+  val point_at : t -> Coord.t -> Point.t
+  val value_at : t -> Coord.t -> Coord.dim2 -> Coord.t
+  val point_and_derivatives : t -> Coord.t -> int -> Point.t array
+end
+
+module Bezier_curve =
+struct
+  type t
+  external of_two_beziers : Bezier.t -> Bezier.t -> t = "bezier_curve_of_two_beziers_wrapper"
+  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 initial_point : t -> Point.t = "bezier_curve_initial_point_wrapper"
+  external final_point : t -> Point.t = "bezier_curve_final_point_wrapper"
+end

File caml2geom.mli

 sig
   type t
   type output_type
+  val default : unit -> t
   val is_zero : t -> bool
   val is_constant : t -> bool
   val is_finite : t -> bool
 module Coord :
 sig
   type t = float
+  type dim2 = X | Y
   val epsilon : t
   external infinity : unit -> t = "infinity_wrapper"
   external are_near : t -> t -> bool = "are_near_wrapper"
 module Point :
 sig
   type t
+  external default : unit -> t = "new_default_point_wrapper"
   external make : Coord.t -> Coord.t -> t = "new_point_wrapper"
   external copy : t -> t = "copy_point_wrapper"
   external coord : t -> int -> Coord.t = "point_coord_wrapper"
 sig
   type t
   type output_type = Coord.t
+  external default : unit -> t = "new_default_bezier_wrapper"
+  external make_order0 : Coord.t -> t = "new_bezier_order0_wrapper"
+  external make_order1 : Coord.t -> Coord.t -> t = "new_bezier_order1_wrapper"
+  external make_order2 : Coord.t -> Coord.t -> Coord.t -> t = "new_bezier_order2_wrapper"
   external make_order3 : Coord.t -> Coord.t -> Coord.t -> Coord.t -> t = "new_bezier_order3_wrapper"
   external is_zero : t -> bool = "bezier_is_zero_wrapper"
   external is_constant : t -> bool = "bezier_is_constant_wrapper"
 end
 
 module Bezier_as_fragment : Fragment
+
+module type Curve =
+sig
+  type t
+  val initial_point : t -> Point.t
+  val final_point : t -> Point.t
+  val is_degenerate : t -> bool
+  val point_at : t -> Coord.t -> Point.t
+  val value_at : t -> Coord.t -> Coord.dim2 -> Coord.t
+  val point_and_derivatives : t -> Coord.t -> int -> Point.t array
+end
+
+module Bezier_curve :
+sig
+  type t
+  external of_two_beziers : Bezier.t -> Bezier.t -> t = "bezier_curve_of_two_beziers_wrapper"
+  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 initial_point : t -> Point.t = "bezier_curve_initial_point_wrapper"
+  external final_point : t -> Point.t = "bezier_curve_final_point_wrapper"
+end

File caml2geom_stubs.c

 
 #include <2geom/affine.h>
 #include <2geom/bezier.h>
+#include <2geom/bezier-curve.h>
 #include <2geom/coord.h>
 #include <2geom/point.h>
 #include <2geom/transforms.h>
 
 //-------------------------------------------------------------------------
 
-inline Geom::Translate translate_from_ml_floats(value _x, value _y)
+#define OPAQUE_P(t, name) (*(t**)Data_custom_val((name)))
+#define OPAQUE_P_ALLOC(t, ops) caml_alloc_custom(&(ops), sizeof(t), 0, 1);
+
+inline Geom::Translate *translate_from_ml_floats(value _x, value _y)
 {
-    return Geom::Translate(Double_val(_x), Double_val(_y));
+    return new Geom::Translate(Double_val(_x), Double_val(_y));
+}
+
+void finalize_translate(value _v)
+{
+    delete OPAQUE_P(Geom::Translate, _v);
 }
 
 static struct custom_operations translate_ops = {
     (char *) "lib2geom.Translate",
-    custom_finalize_default,
+    finalize_translate,
     custom_compare_default,
     custom_hash_default,
     custom_serialize_default,
     custom_deserialize_default
 };
 
-inline Geom::Point point_from_ml_floats(value _x, value _y)
+inline Geom::Point *point_from_ml_floats(value _x, value _y)
 {
-    return Geom::Point(Double_val(_x), Double_val(_y));
+    return new Geom::Point(Double_val(_x), Double_val(_y));
+}
+
+void finalize_point(value _v)
+{
+    delete OPAQUE_P(Geom::Point, _v);
 }
 
 static struct custom_operations point_ops = {
     (char *) "lib2geom.Point",
-    custom_finalize_default,
+    finalize_point,
     custom_compare_default,
     custom_hash_default,
     custom_serialize_default,
     custom_deserialize_default
 };
 
+void finalize_bezier(value _v)
+{
+    delete OPAQUE_P(Geom::Bezier, _v);
+}
+
 static struct custom_operations bezier_ops = {
     (char *) "lib2geom.Bezier",
+    finalize_bezier,
+    custom_compare_default,
+    custom_hash_default,
+    custom_serialize_default,
+    custom_deserialize_default
+};
+
+void finalize_bezier_curve(value _v)
+{
+    delete OPAQUE_P(Geom::BezierCurve, _v);
+}
+
+static struct custom_operations bezier_curve_ops = {
+    (char *) "lib2geom.Bezier_curve",
     custom_finalize_default,
     custom_compare_default,
     custom_hash_default,
 {
     CAMLparam2(_x, _y);
     CAMLlocal1(_t);
-    _t = caml_alloc_custom(&translate_ops, sizeof(Geom::Translate), 0, 1);
-    *(Geom::Translate *)Data_custom_val(_t) = translate_from_ml_floats(_x, _y);
+    _t = OPAQUE_P_ALLOC(Geom::Translate, translate_ops);
+    OPAQUE_P(Geom::Translate, _t) = translate_from_ml_floats(_x, _y);
     CAMLreturn(_t);
 }
 
 {
     CAMLparam1(_p);
     CAMLlocal1(_t);
-    double x = Geom::Point(*(Geom::Point *)Data_custom_val(_p))[0];
-    double y = Geom::Point(*(Geom::Point *)Data_custom_val(_p))[1];
-    _t = caml_alloc_custom(&translate_ops, sizeof(Geom::Translate), 0, 1);
-    *(Geom::Translate *)Data_custom_val(_t) = Geom::Translate(x, y);
+    double x = Geom::Point(*(Geom::Point*)Data_custom_val(_p))[0];
+    double y = Geom::Point(*(Geom::Point*)Data_custom_val(_p))[1];
+    _t = OPAQUE_P_ALLOC(Geom::Translate, translate_ops);
+    OPAQUE_P(Geom::Translate, _t) = new Geom::Translate(x, y);
     CAMLreturn(_t);
 }
 
 //-------------------------------------------------------------------------
 
+extern "C" CAMLprim value new_default_point_wrapper(void)
+{
+    CAMLparam0();
+    CAMLlocal1(_p);
+    _p = OPAQUE_P_ALLOC(Geom::Point, point_ops);
+    OPAQUE_P(Geom::Point, _p) = new Geom::Point();
+    CAMLreturn(_p);
+}
+
 extern "C" CAMLprim value new_point_wrapper(value _x, value _y)
 {
     CAMLparam2(_x, _y);
     CAMLlocal1(_p);
-    _p = caml_alloc_custom(&point_ops, sizeof(Geom::Point), 0, 1);
-    *(Geom::Point *)Data_custom_val(_p) = point_from_ml_floats(_x, _y);
+    _p = OPAQUE_P_ALLOC(Geom::Point, point_ops);
+    OPAQUE_P(Geom::Point, _p) = point_from_ml_floats(_x, _y);
     CAMLreturn(_p);
 }
 
 {
     CAMLparam1(_p);
     CAMLlocal1(_p_new);
-    _p_new = caml_alloc_custom(&point_ops, sizeof(Geom::Point), 0, 1);
-    *(Geom::Point *)Data_custom_val(_p_new) =
-        Geom::Point(*(Geom::Point *)Data_custom_val(_p));
+    _p_new = OPAQUE_P_ALLOC(Geom::Point, point_ops);
+    OPAQUE_P(Geom::Point, _p_new) = new Geom::Point(*OPAQUE_P(Geom::Point, _p));
     CAMLreturn(_p_new);
 }
 
     int i = Int_val(_i);
     if (i < 0 || 1 < i)
         caml_invalid_argument("Point.coord index out of range");
-    CAMLreturn(caml_copy_double((*(Geom::Point *)Data_custom_val(_p))[i]));
+    CAMLreturn(caml_copy_double((*OPAQUE_P(Geom::Point, _p))[i]));
 }
 
 extern "C" CAMLprim value set_point_coord_wrapper(value _p, value _i, value _v)
     int i = Int_val(_i);
     if (i < 0 || 1 < i)
         caml_invalid_argument("Point.coord index out of range");
-    (*(Geom::Point *)Data_custom_val(_p))[i] = Double_val(_v);
+    (*OPAQUE_P(Geom::Point, _p))[i] = Double_val(_v);
     CAMLreturn(Val_unit);
 }
 
 extern "C" CAMLprim value point_length_wrapper(value _p)
 {
     CAMLparam1(_p);
-    CAMLreturn(caml_copy_double((*(Geom::Point *)Data_custom_val(_p)).length()));
+    CAMLreturn(caml_copy_double(OPAQUE_P(Geom::Point, _p)->length()));
 }
 
 extern "C" CAMLprim value point_normalize_wrapper(value _p)
 {
     CAMLparam1(_p);
-    (*(Geom::Point *)Data_custom_val(_p)).normalize();
+    OPAQUE_P(Geom::Point, _p)->normalize();
     CAMLreturn(Val_unit);
 }
 
     {                                                                   \
         CAMLparam1(_p);                                                 \
         CAMLlocal1(_p_new);                                             \
-        _p_new = caml_alloc_custom(&point_ops, sizeof(Geom::Point), 0, 1); \
-        *(Geom::Point *)Data_custom_val(_p_new) =                       \
-            (*(Geom::Point *)Data_custom_val(_p)).op();                 \
+        _p_new = OPAQUE_P_ALLOC(Geom::Point, point_ops);                \
+        OPAQUE_P(Geom::Point, _p_new) =                                 \
+            new Geom::Point(OPAQUE_P(Geom::Point, _p)->op());           \
         CAMLreturn(_p_new);                                             \
     }
 
     extern "C" CAMLprim value name(value _p, value _other)              \
     {                                                                   \
         CAMLparam2(_p, _other);                                         \
-        (*(Geom::Point *)Data_custom_val(_p)).op(*(Geom::Point *)Data_custom_val(_other)); \
+        OPAQUE_P(Geom::Point, _p)->op(*OPAQUE_P(Geom::Point, _other)); \
         CAMLreturn(Val_unit);                                           \
     }
 
     extern "C" CAMLprim value name(value _p, value _other)              \
     {                                                                   \
         CAMLparam2(_p, _other);                                         \
-        (*(Geom::Point *)Data_custom_val(_p)).op(Double_val(_other));   \
+        OPAQUE_P(Geom::Point, _p)->op(Double_val(_other));       \
         CAMLreturn(Val_unit);                                           \
     }
 
 
 //-------------------------------------------------------------------------
 
+extern "C" CAMLprim value new_default_bezier_wrapper(void)
+{
+    CAMLparam0();
+    CAMLlocal1(_bez);
+    _bez = OPAQUE_P_ALLOC(Geom::Bezier, bezier_ops);
+    OPAQUE_P(Geom::Bezier, _bez) = new Geom::Bezier();
+    CAMLreturn(_bez);
+}
+
+extern "C" CAMLprim value new_bezier_order0_wrapper(value _c0)
+{
+    CAMLparam1(_c0);
+    CAMLlocal1(_bez);
+    _bez = OPAQUE_P_ALLOC(Geom::Bezier, bezier_ops);
+    OPAQUE_P(Geom::Bezier, _bez) = new Geom::Bezier(Double_val(_c0));
+    CAMLreturn(_bez);
+}
+
+extern "C" CAMLprim value new_bezier_order1_wrapper(value _c0, value _c1)
+{
+    CAMLparam2(_c0, _c1);
+    CAMLlocal1(_bez);
+    _bez = OPAQUE_P_ALLOC(Geom::Bezier, bezier_ops);
+    OPAQUE_P(Geom::Bezier, _bez) = new Geom::Bezier(Double_val(_c0), Double_val(_c1));
+    CAMLreturn(_bez);
+}
+
+extern "C" CAMLprim value new_bezier_order2_wrapper(value _c0, value _c1, value _c2)
+{
+    CAMLparam3(_c0, _c1, _c2);
+    CAMLlocal1(_bez);
+    _bez = OPAQUE_P_ALLOC(Geom::Bezier, bezier_ops);
+    OPAQUE_P(Geom::Bezier, _bez) =
+        new Geom::Bezier(Double_val(_c0), Double_val(_c1), Double_val(_c2));
+    CAMLreturn(_bez);
+}
+
 extern "C" CAMLprim value new_bezier_order3_wrapper(value _c0, value _c1, value _c2, value _c3)
 {
     CAMLparam4(_c0, _c1, _c2, _c3);
     CAMLlocal1(_bez);
-    _bez = caml_alloc_custom(&bezier_ops, sizeof(Geom::Bezier), 0, 1);
-    *(Geom::Bezier *)Data_custom_val(_bez) = Geom::Bezier(Double_val(_c0), Double_val(_c1),
-                                                        Double_val(_c2), Double_val(_c3));
+    _bez = OPAQUE_P_ALLOC(Geom::Bezier, bezier_ops);
+    OPAQUE_P(Geom::Bezier, _bez) =
+        new Geom::Bezier(Double_val(_c0), Double_val(_c1), Double_val(_c2), Double_val(_c3));
     CAMLreturn(_bez);
 }
 
     extern "C" CAMLprim value name(value _bez)                          \
     {                                                                   \
         CAMLparam1(_bez);                                               \
-        CAMLreturn(typeconv((*(Geom::Bezier *)Data_custom_val(_bez)).func())); \
+        CAMLreturn(typeconv(OPAQUE_P(Geom::Bezier, _bez)->func())); \
     }
 
 bezier_getval_wrapper(bezier_is_zero_wrapper, isZero, Val_bool);
 extern "C" CAMLprim value bezier_value_at_wrapper(value _bez, value _t)
 {
     CAMLparam2(_bez, _t);
-    CAMLreturn(caml_copy_double((*(Geom::Bezier *)Data_custom_val(_bez)).valueAt(Double_val(_t))));
+    CAMLreturn(caml_copy_double(OPAQUE_P(Geom::Bezier, _bez)->valueAt(Double_val(_t))));
 }
 
 //-------------------------------------------------------------------------
+
+extern "C" CAMLprim value bezier_curve_of_two_beziers_wrapper(value _bez0, value _bez1)
+{
+    CAMLparam2(_bez0, _bez1);
+    CAMLlocal1(_bezcurve);
+    _bezcurve = OPAQUE_P_ALLOC(Geom::BezierCurve, bezier_curve_ops);
+    *(Geom::BezierCurve**)Data_custom_val(_bezcurve) =
+        new Geom::BezierCurve(*(Geom::Bezier*)Data_custom_val(_bez0),
+                              *(Geom::Bezier*)Data_custom_val(_bez1));
+    CAMLreturn(_bezcurve);
+}
+
+extern "C" CAMLprim value bezier_curve_of_two_points_wrapper(value _p0, value _p1)
+{
+    CAMLparam2(_p0, _p1);
+    CAMLlocal1(_bezcurve);
+    _bezcurve = OPAQUE_P_ALLOC(Geom::BezierCurve, bezier_curve_ops);
+    *(Geom::BezierCurve**)Data_custom_val(_bezcurve) =
+        new Geom::BezierCurve(*(Geom::Point*)Data_custom_val(_p0),
+                              *(Geom::Point*)Data_custom_val(_p1));
+    CAMLreturn(_bezcurve);
+}
+
+extern "C" CAMLprim value bezier_curve_of_three_points_wrapper(value _p0, value _p1, value _p2)
+{
+    CAMLparam3(_p0, _p1, _p2);
+    CAMLlocal1(_bezcurve);
+    _bezcurve = OPAQUE_P_ALLOC(Geom::BezierCurve, bezier_curve_ops);
+    *(Geom::BezierCurve**)Data_custom_val(_bezcurve) =
+        new Geom::BezierCurve(*(Geom::Point*)Data_custom_val(_p0),
+                              *(Geom::Point*)Data_custom_val(_p1),
+                              *(Geom::Point*)Data_custom_val(_p2));
+    CAMLreturn(_bezcurve);
+}
+
+extern "C" CAMLprim value bezier_curve_of_four_points_wrapper(value _p0, value _p1, value _p2, value _p3)
+{
+    CAMLparam4(_p0, _p1, _p2, _p3);
+    CAMLlocal1(_bezcurve);
+    _bezcurve = OPAQUE_P_ALLOC(Geom::BezierCurve, bezier_curve_ops);
+    *(Geom::BezierCurve**)Data_custom_val(_bezcurve) =
+        new Geom::BezierCurve(*(Geom::Point*)Data_custom_val(_p0),
+                              *(Geom::Point*)Data_custom_val(_p1),
+                              *(Geom::Point*)Data_custom_val(_p2),
+                              *(Geom::Point*)Data_custom_val(_p3));
+    CAMLreturn(_bezcurve);
+}
+
+extern "C" CAMLprim value bezier_curve_initial_point_wrapper(value _bezcurve)
+{
+    CAMLparam1(_bezcurve);
+    CAMLlocal1(_p);
+    _p = OPAQUE_P_ALLOC(Geom::Point, point_ops);
+    *(Geom::Point*)Data_custom_val(_p) =
+        (*(Geom::BezierCurve**)Data_custom_val(_bezcurve))->initialPoint();
+    CAMLreturn(_p);
+}
+
+extern "C" CAMLprim value bezier_curve_final_point_wrapper(value _bezcurve)
+{
+    CAMLparam1(_bezcurve);
+    CAMLlocal1(_p);
+    _p = OPAQUE_P_ALLOC(Geom::Point, point_ops);
+    *(Geom::Point*)Data_custom_val(_p) = OPAQUE_P(Geom::BezierCurve, _bezcurve)->finalPoint();
+    CAMLreturn(_p);
+}
+
+//-------------------------------------------------------------------------
 let _ = printf "at 0.75 -> %f\n" (Bezier.value_at bez 0.75) ;;
 
 (*-----------------------------------------------------------------------*)
+
+let bezcurve =
+  Bezier_curve.of_four_points (Point.make 0. 0.) (Point.make 10. 10.) (Point.make 15. 5.) (Point.make 20. 1.) ;;
+let _ =
+  printf "initial_point = (%f,%f)\n" (Point.coord (Bezier_curve.initial_point bezcurve) 0)
+    (Point.coord (Bezier_curve.initial_point bezcurve) 1) ;;
+let _ =
+  printf "final_point = (%f,%f)\n" (Point.coord (Bezier_curve.final_point bezcurve) 0)
+    (Point.coord (Bezier_curve.final_point bezcurve) 1) ;;
+
+(*-----------------------------------------------------------------------*)