# package ppx_deriving_scad

## Install

## Dune Dependency

## Authors

## Maintainers

## Sources

`sha256=2b1ec77fefe7770ac04efd9cbbb92aa864f4843070ef0fc3937880e593d591b2`

`sha512=0c13527fdbdf9623837d51a24e282784b796c7f5e4ae38d94004624ec3745ccf84ac72affc2e84bf8aaaafec9c27301b1a73fd08e678f76e79337e6137906140`

## Description

[@@deriving scad] generates functions for the
spatial transformation of user defined abstract and record types containing
types for which said transformation functions are defined, in particular, the
`Scad.t`

and `Vec3.t`

types of the Scad_ml library.

## Published: 31 Oct 2021

## README

## [@@deriving scad]

`ppx_deriving_scad`

is a PPX deriver that generates functions for the spatial transformation of user defined abstract and record types containing types for which said transformation functions are defined, in particular, the `Scad.t`

and `Vec3.t`

types of the Scad_ml library.

**For example:**

```
open Scad_ml
type mark =
{ scad : Scad.three_d Scad.t
; origin : Vec3.t
}
[@@deriving scad]
```

**Generates:**

```
val translate_mark : Vec3.t -> mark -> mark
val scale_mark : Vec3.t -> mark -> mark
val rotate_mark : Vec3.t -> mark -> mark
val rotate_about_pt_mark : Vec3.t -> Vec3.t -> mark -> mark
val quaternion_mark : Quaternion.t -> mark -> mark
val quaternion_about_pt_mark : Quaternion.t -> Vec3.t -> mark -> mark
val mirror_mark : Vec3.t -> mark -> mark
```

If the name of the type being derived is `t`

, then the functions generated (and those required to be present for the types inside of a type/record being derived) will be given unqualified names. Notable exceptions to this rule, are the 2D and 3D `Scad.t`

aliases `Scad.d2`

and `Scad.d3`

, which use the same unquailified basic transformation functions in the `Scad`

module. For example, applying `[@@deriving scad]`

to a lone record type `t`

would give a module that adhered to the following signature.

```
open Scad_ml
module Mark : sig
type t =
{ scad : Scad.d3
; origin : Vec3.t
}
val translate : Vec3.t -> t -> t
val scale : Vec3.t -> t -> t
val rotate : Vec3.t -> t -> t
val rotate_about_pt : Vec3.t -> Vec3.t -> t -> t
val quaternion : Quaternion.t -> t -> t
val quaternion_about_pt : Quaternion.t -> Vec3.t -> t -> t
val mirror : Vec3.t -> t -> t
end = struct
type t =
{ scad : Scad.three_d Scad.t
; origin : Vec3.t
}
[@@deriving scad]
end
```

### Basic monadic types and tuples

The `list`

, `option`

, and `result`

types, as well as **tuples**, are automatically mapped over, without any additional annotation or functions provided.

```
module Points : sig
type t = Vec3.t list
val translate : Vec3.t -> Vec3.t list -> Vec3.t list
val scale : Vec3.t -> Vec3.t list -> Vec3.t list
val rotate : Vec3.t -> Vec3.t list -> Vec3.t list
val rotate_about_pt : Vec3.t -> Vec3.t -> Vec3.t list -> Vec3.t list
val quaternion : Quaternion.t -> Vec3.t list -> Vec3.t list
val quaternion_about_pt : Quaternion.t -> Vec3.t -> Vec3.t list -> Vec3.t list
val mirror : Vec3.t -> Vec3.t list -> Vec3.t list
end = struct
type t = Vec3.t list [@@deriving scad]
end
```

### Other mappable types

By default, `[@@deriving scad]`

will attempt to map over constructors other than the above basic types by using applying the `map`

function of the relevant module, or for the non-`t`

named type, using the same naming conventions as explained above.

```
module IntMap = Map.Make (Int)
type vec_map = Vec3.t IntMap.t [@@deriving scad]
```

Here, `IntMap.map`

will be used to apply transformations to the contained `Vec3.t`

elements. The expected map function should obey the convention of the function `f`

being the first *positional* argument. If you are following the conventions of Jane Street and/or have `base`

/`core`

open, then you may use `[@@deriving scad_jane]`

which defaults to expecting `map`

functions to accept a keyword parameter `~f`

instead. If you are deriving a record containing types with mixed mapping conventions, you can make use of the `[@scad.map]`

and `[@scad.mapf]`

attributes to specify fields that do not match your default convention.

If the constructor type is not named `t`

as in this example, then this ppx will attempt to use a function with the suffix `_map`

. For example, if the type above was instead `Vec3.t int_map`

, the function `int_map_map`

will be expected in the scope of the derived type.

### Intf generation

Annotating types in module sigs and `.mli`

files will generate the relevant type signatures.

```
module MaybeScad : sig
type 's t = 's Scad.t option [@@deriving scad]
end = struct
type 's t = 's Scad.t option [@@deriving scad]
end
```

### Attributes

#### [@scad.unit]

This annotation should be applied to abstract types and fields which represent unit vector. Types/fields marked with this will not be subject to transformations that would cause them to lose thier identity as such, or rotate about anything other than the world origin. Thus:

translate and scale will not be applied (identity function instead)

{rotate,quaternion}_about_pt will be replaced by their pivot translation free counterparts

**Usage:**

```
type plane =
{ scad : Scad.three_d Scad.t
; normal : Vec3.t [@scad.unit]
} [@@deriving scad]
```

In this case the following would hold:

```
let true =
let plane =
{ scad = Scad.cube (10., 10., 0.001)
; normal = 0., 0., 1.
}
in
let trans = plane_translate (5., 5., 0.) plane in
Vec3.equal plane.normal trans.normal
```

#### [@scad.ignore]

This annotation marks a field (in a record, not applicable to abstract types) to be ignored by all generated transformations. This is useful for ignoring whatever flags/configuration data that you want to carry around along with your type for which the relevant functions have not been implemented.

**Usage:**

```
type mark =
{ scad : Scad.three_d Scad.t
; origin : Vec3.t
; id : int [@scad.ignore]
} [@@deriving scad]
```

#### [@scad.map] and [@scad.mapf]

This annotation marks a type/field for which the transformable type is contained within a mappable type (aka functor), for which `map`

is defined, and whose parameter convention differs from the default specified by the deriver attached to the type declaration.

`[@@deriving scad]`

-> positional`f`

expected (e.g.`map f`

)`[@@deriving scad_jane]`

-> keyword`~f`

expected (e.g.`map ~f`

)

Thus, `[@scad.map]`

indicates that relevant `map`

functions will obey the convention of `f`

being the first *positional* argument (overiding `[@@deriving scad_jane]`

), whereas `[@scad.mapf]`

indicates that a keyword argument of `~f`

is expected instead (overiding `[@@deriving scad]`

). These attributes are not required for the `list`

, `option`

, and `result`

types, as they do not rely on any functions in scope.

**Usage:**

```
open Base
module IntMap = Caml.Map.Make (Int)
module MixedMaps = struct
type t =
{ std : Vec3.t IntMap.t
; jane : (Vec3.t Map.M(Int).t [@scad.mapf])
} [@@deriving scad]
end
```