Skip to main content

src/gleamscad.erl

-module(gleamscad).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/gleamscad.gleam").
-export([union/1, difference/1, intersection/1, translate/4, rotate/4, scale/4, mirror/4, circle/2, square/3, polygon/1, cube/2, cube3/4, sphere/2, cylinder/4, cylinder2/5, custom_code/1, linear_extrude/6, to_openscad/1]).
-export_type([radius_or_diameter/0, centered_or_not/0, open_s_c_a_d_expr/0]).

-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.

-type radius_or_diameter() :: radius | diameter.

-type centered_or_not() :: centered | not_centered.

-type open_s_c_a_d_expr() :: {union, list(open_s_c_a_d_expr())} |
    {difference, list(open_s_c_a_d_expr())} |
    {intersection, list(open_s_c_a_d_expr())} |
    {translate, open_s_c_a_d_expr(), {float(), float(), float()}} |
    {rotate, open_s_c_a_d_expr(), {float(), float(), float()}} |
    {scale, open_s_c_a_d_expr(), {float(), float(), float()}} |
    {mirror, open_s_c_a_d_expr(), {float(), float(), float()}} |
    {circle, float(), radius_or_diameter()} |
    {square, float(), float(), centered_or_not()} |
    {polygon, list({float(), float()})} |
    {cube, {float(), float(), float()}, centered_or_not()} |
    {sphere, float(), radius_or_diameter()} |
    {cylinder, float(), float(), radius_or_diameter(), centered_or_not()} |
    {cylinder2,
        float(),
        float(),
        float(),
        radius_or_diameter(),
        centered_or_not()} |
    {linear_extrude,
        open_s_c_a_d_expr(),
        float(),
        centered_or_not(),
        float(),
        float(),
        float()} |
    {custom_code, binary()}.

-file("src/gleamscad.gleam", 77).
?DOC(" Create a union of shapes\n").
-spec union(list(open_s_c_a_d_expr())) -> open_s_c_a_d_expr().
union(Expressions) ->
    {union, Expressions}.

-file("src/gleamscad.gleam", 82).
?DOC(" Create a difference of shapes\n").
-spec difference(list(open_s_c_a_d_expr())) -> open_s_c_a_d_expr().
difference(Expressions) ->
    {difference, Expressions}.

-file("src/gleamscad.gleam", 87).
?DOC(" Creates an intersection of shapes\n").
-spec intersection(list(open_s_c_a_d_expr())) -> open_s_c_a_d_expr().
intersection(Expressions) ->
    {intersection, Expressions}.

-file("src/gleamscad.gleam", 92).
?DOC(" Translate (move) a shape\n").
-spec translate(open_s_c_a_d_expr(), float(), float(), float()) -> open_s_c_a_d_expr().
translate(Expr, X, Y, Z) ->
    {translate, Expr, {X, Y, Z}}.

-file("src/gleamscad.gleam", 102).
?DOC(" Rotate a shape\n").
-spec rotate(open_s_c_a_d_expr(), float(), float(), float()) -> open_s_c_a_d_expr().
rotate(Expr, X, Y, Z) ->
    {rotate, Expr, {X, Y, Z}}.

-file("src/gleamscad.gleam", 112).
?DOC(" Scales a shape\n").
-spec scale(open_s_c_a_d_expr(), float(), float(), float()) -> open_s_c_a_d_expr().
scale(Expr, X, Y, Z) ->
    {scale, Expr, {X, Y, Z}}.

-file("src/gleamscad.gleam", 117).
?DOC(" Mirrors a shape\n").
-spec mirror(open_s_c_a_d_expr(), float(), float(), float()) -> open_s_c_a_d_expr().
mirror(Expr, X, Y, Z) ->
    {mirror, Expr, {X, Y, Z}}.

-file("src/gleamscad.gleam", 127).
?DOC(" Draws a 2d circle\n").
-spec circle(float(), radius_or_diameter()) -> open_s_c_a_d_expr().
circle(Value, Rod) ->
    {circle, Value, Rod}.

-file("src/gleamscad.gleam", 132).
?DOC(" Draws a 2d square\n").
-spec square(float(), float(), centered_or_not()) -> open_s_c_a_d_expr().
square(Width, Height, Center) ->
    {square, Width, Height, Center}.

-file("src/gleamscad.gleam", 141).
?DOC(" Draws a 2d polygon\n").
-spec polygon(list({float(), float()})) -> open_s_c_a_d_expr().
polygon(Polygons) ->
    {polygon, Polygons}.

-file("src/gleamscad.gleam", 146).
?DOC(" Creates a 3d cube with all sides of equal length\n").
-spec cube(float(), centered_or_not()) -> open_s_c_a_d_expr().
cube(Size, Center) ->
    {cube, {Size, Size, Size}, Center}.

-file("src/gleamscad.gleam", 151).
?DOC(" Creates a 3d cube\n").
-spec cube3(float(), float(), float(), centered_or_not()) -> open_s_c_a_d_expr().
cube3(Width, Depth, Height, Center) ->
    {cube, {Width, Depth, Height}, Center}.

-file("src/gleamscad.gleam", 161).
?DOC(" Creates a 3d sphere\n").
-spec sphere(float(), radius_or_diameter()) -> open_s_c_a_d_expr().
sphere(Value, Rod) ->
    {sphere, Value, Rod}.

-file("src/gleamscad.gleam", 166).
?DOC(" Creates a 3d cylinder\n").
-spec cylinder(float(), float(), radius_or_diameter(), centered_or_not()) -> open_s_c_a_d_expr().
cylinder(Height, Value, Rod, Center) ->
    {cylinder, Height, Value, Rod, Center}.

-file("src/gleamscad.gleam", 176).
?DOC(" Creates a 3d cylinder. Enables you to pass different diameters/radii for top and bottom\n").
-spec cylinder2(
    float(),
    float(),
    float(),
    radius_or_diameter(),
    centered_or_not()
) -> open_s_c_a_d_expr().
cylinder2(Height, Value1, Value2, Rod, Center) ->
    {cylinder2, Height, Value1, Value2, Rod, Center}.

-file("src/gleamscad.gleam", 187).
?DOC(" Allows for adding custom code\n").
-spec custom_code(binary()) -> open_s_c_a_d_expr().
custom_code(Code) ->
    {custom_code, Code}.

-file("src/gleamscad.gleam", 191).
-spec linear_extrude(
    open_s_c_a_d_expr(),
    float(),
    centered_or_not(),
    float(),
    float(),
    float()
) -> open_s_c_a_d_expr().
linear_extrude(Expr, Height, Center, Convexity, Twist, Slices) ->
    {linear_extrude, Expr, Height, Center, Convexity, Twist, Slices}.

-file("src/gleamscad.gleam", 217).
-spec centered_or_not_to_string(centered_or_not()) -> binary().
centered_or_not_to_string(Value) ->
    _pipe = case Value of
        centered ->
            true;

        not_centered ->
            false
    end,
    _pipe@1 = gleam@bool:to_string(_pipe),
    string:lowercase(_pipe@1).

-file("src/gleamscad.gleam", 227).
?DOC(" Exports the data to a string, containing OpenSCAD code\n").
-spec to_openscad(open_s_c_a_d_expr()) -> binary().
to_openscad(Expr) ->
    case Expr of
        {union, Expressions} ->
            _pipe = fmglee:new(<<"union(){\n%s\n}"/utf8>>),
            _pipe@3 = fmglee:s(
                _pipe,
                begin
                    _pipe@1 = Expressions,
                    _pipe@2 = gleam@list:map(_pipe@1, fun to_openscad/1),
                    gleam@string:join(_pipe@2, <<"\n"/utf8>>)
                end
            ),
            fmglee:build(_pipe@3);

        {difference, Expressions@1} ->
            _pipe@4 = fmglee:new(<<"difference(){\n%s\n}"/utf8>>),
            _pipe@7 = fmglee:s(
                _pipe@4,
                begin
                    _pipe@5 = Expressions@1,
                    _pipe@6 = gleam@list:map(_pipe@5, fun to_openscad/1),
                    gleam@string:join(_pipe@6, <<"\n"/utf8>>)
                end
            ),
            fmglee:build(_pipe@7);

        {intersection, Expressions@2} ->
            _pipe@8 = fmglee:new(<<"intersection(){\n%s\n}"/utf8>>),
            _pipe@11 = fmglee:s(
                _pipe@8,
                begin
                    _pipe@9 = Expressions@2,
                    _pipe@10 = gleam@list:map(_pipe@9, fun to_openscad/1),
                    gleam@string:join(_pipe@10, <<"\n"/utf8>>)
                end
            ),
            fmglee:build(_pipe@11);

        {translate, Expr@1, Vector} ->
            build_command(Expr@1, <<"translate"/utf8>>, Vector);

        {rotate, Expr@2, Angle} ->
            build_command(Expr@2, <<"rotate"/utf8>>, Angle);

        {scale, Expr@3, Vector@1} ->
            build_command(Expr@3, <<"scale"/utf8>>, Vector@1);

        {mirror, Expr@4, Vector@2} ->
            build_command(Expr@4, <<"mirror"/utf8>>, Vector@2);

        {circle, Value, Rod} ->
            case Rod of
                radius ->
                    _pipe@12 = fmglee:new(<<"circle(r=%f);"/utf8>>),
                    _pipe@13 = fmglee:f(_pipe@12, Value),
                    fmglee:build(_pipe@13);

                diameter ->
                    _pipe@14 = fmglee:new(<<"circle(d=%f);"/utf8>>),
                    _pipe@15 = fmglee:f(_pipe@14, Value),
                    fmglee:build(_pipe@15)
            end;

        {square, Width, Height, Center} ->
            _pipe@16 = fmglee:new(
                <<"square(width=%f,height=%f,center=%s);"/utf8>>
            ),
            _pipe@17 = fmglee:f(_pipe@16, Width),
            _pipe@18 = fmglee:f(_pipe@17, Height),
            _pipe@19 = fmglee:s(_pipe@18, centered_or_not_to_string(Center)),
            fmglee:build(_pipe@19);

        {polygon, Polygons} ->
            _pipe@20 = fmglee:new(<<"polygon(points=[%s]);"/utf8>>),
            _pipe@26 = fmglee:s(
                _pipe@20,
                begin
                    _pipe@21 = Polygons,
                    _pipe@25 = gleam@list:map(
                        _pipe@21,
                        fun(Point) -> _pipe@22 = fmglee:new(<<"[%f,%f]"/utf8>>),
                            _pipe@23 = fmglee:f(
                                _pipe@22,
                                erlang:element(1, Point)
                            ),
                            _pipe@24 = fmglee:f(
                                _pipe@23,
                                erlang:element(2, Point)
                            ),
                            fmglee:build(_pipe@24) end
                    ),
                    gleam@string:join(_pipe@25, <<","/utf8>>)
                end
            ),
            fmglee:build(_pipe@26);

        {cube, Size, Center@1} ->
            {W, D, H} = Size,
            _pipe@27 = fmglee:new(
                <<"cube(size=[%f, %f, %f], center=%s);"/utf8>>
            ),
            _pipe@28 = fmglee:f(_pipe@27, W),
            _pipe@29 = fmglee:f(_pipe@28, D),
            _pipe@30 = fmglee:f(_pipe@29, H),
            _pipe@31 = fmglee:s(_pipe@30, centered_or_not_to_string(Center@1)),
            fmglee:build(_pipe@31);

        {sphere, Value@1, Rod@1} ->
            case Rod@1 of
                radius ->
                    _pipe@32 = fmglee:new(<<"sphere(r=%f);"/utf8>>),
                    _pipe@33 = fmglee:f(_pipe@32, Value@1),
                    fmglee:build(_pipe@33);

                diameter ->
                    _pipe@34 = fmglee:new(<<"sphere(d=%f);"/utf8>>),
                    _pipe@35 = fmglee:f(_pipe@34, Value@1),
                    fmglee:build(_pipe@35)
            end;

        {cylinder, Height@1, Value@2, Rod@2, Center@2} ->
            case Rod@2 of
                radius ->
                    _pipe@36 = fmglee:new(
                        <<"cylinder(h=%f,r=%f,center=%s);"/utf8>>
                    ),
                    _pipe@37 = fmglee:f(_pipe@36, Height@1),
                    _pipe@38 = fmglee:f(_pipe@37, Value@2),
                    _pipe@39 = fmglee:s(
                        _pipe@38,
                        centered_or_not_to_string(Center@2)
                    ),
                    fmglee:build(_pipe@39);

                diameter ->
                    _pipe@40 = fmglee:new(
                        <<"cylinder(h=%f,d=%f,center=%s);"/utf8>>
                    ),
                    _pipe@41 = fmglee:f(_pipe@40, Height@1),
                    _pipe@42 = fmglee:f(_pipe@41, Value@2),
                    _pipe@43 = fmglee:s(
                        _pipe@42,
                        centered_or_not_to_string(Center@2)
                    ),
                    fmglee:build(_pipe@43)
            end;

        {cylinder2, Height@2, Value1, Value2, Rod@3, Center@3} ->
            case Rod@3 of
                radius ->
                    _pipe@44 = fmglee:new(
                        <<"cylinder(h=%f,r1=%f,r2=%f,center=%s);"/utf8>>
                    ),
                    _pipe@45 = fmglee:f(_pipe@44, Height@2),
                    _pipe@46 = fmglee:f(_pipe@45, Value1),
                    _pipe@47 = fmglee:f(_pipe@46, Value2),
                    _pipe@48 = fmglee:s(
                        _pipe@47,
                        centered_or_not_to_string(Center@3)
                    ),
                    fmglee:build(_pipe@48);

                diameter ->
                    _pipe@49 = fmglee:new(
                        <<"cylinder(h=%f,d1=%f,d2=%f,center=%s);"/utf8>>
                    ),
                    _pipe@50 = fmglee:f(_pipe@49, Height@2),
                    _pipe@51 = fmglee:f(_pipe@50, Value1),
                    _pipe@52 = fmglee:f(_pipe@51, Value2),
                    _pipe@53 = fmglee:s(
                        _pipe@52,
                        centered_or_not_to_string(Center@3)
                    ),
                    fmglee:build(_pipe@53)
            end;

        {linear_extrude, Expr@5, Height@3, Center@4, Convexity, Twist, Slices} ->
            _pipe@54 = fmglee:new(
                <<"linear_extrude(height=%f,center=%s,convexity=%f,twist=%f,slices=%f){\n%s\n}"/utf8>>
            ),
            _pipe@55 = fmglee:f(_pipe@54, Height@3),
            _pipe@56 = fmglee:s(_pipe@55, centered_or_not_to_string(Center@4)),
            _pipe@57 = fmglee:f(_pipe@56, Convexity),
            _pipe@58 = fmglee:f(_pipe@57, Twist),
            _pipe@59 = fmglee:f(_pipe@58, Slices),
            _pipe@60 = fmglee:s(_pipe@59, to_openscad(Expr@5)),
            fmglee:build(_pipe@60);

        {custom_code, Code} ->
            Code
    end.

-file("src/gleamscad.gleam", 203).
?DOC(" Helper function, for creating some of the strings\n").
-spec build_command(open_s_c_a_d_expr(), binary(), {float(), float(), float()}) -> binary().
build_command(Expr, Command, Vector) ->
    _pipe = fmglee:new(<<"%s([%f, %f, %f]){\n%s\n}"/utf8>>),
    _pipe@1 = fmglee:s(_pipe, Command),
    _pipe@2 = fmglee:f(_pipe@1, erlang:element(1, Vector)),
    _pipe@3 = fmglee:f(_pipe@2, erlang:element(2, Vector)),
    _pipe@4 = fmglee:f(_pipe@3, erlang:element(3, Vector)),
    _pipe@5 = fmglee:s(_pipe@4, to_openscad(Expr)),
    fmglee:build(_pipe@5).