Entry 3211

why can't I just leave this field empty?

   

Submitted by bz on Feb. 15, 2010 at 10:27 a.m.
Language: Erlang. Code size: 2.9 KB.

-module(snowflake).
-author(baltazar).
-compile(export_all).

-define(RELATIVE_PATH(Step), [{Step, 0}, {0, -Step}, {Step, 0}, {0, Step}, {0, Step}, {Step, 0}, {0, -Step}, {Step, 0}]).
-define(ABSOLUTE_ANGLES, [-90, 0, 90, 90, 0, -90, 0, 0]).
-define(WINDOW_WIDTH, 900).
-define(WINDOW_HEIGHT, 900).

init() ->
    S = gs:start(),
    Win = gs:create(window, S, [{width, ?WINDOW_WIDTH}, {height, ?WINDOW_HEIGHT}, {map, true}]),
    Canvas = gs:canvas(Win, [{x, 0}, {y, 0}, {width, ?WINDOW_WIDTH}, {height, ?WINDOW_HEIGHT}]),
    draw_snowflake(Canvas, {200, 200}, 500, 1),
    loop(),
    halt(0).

degree_to_radian(Degree) -> (Degree * math:pi()) / 180.

draw_snowflake(Canvas, {X, Y}, Size, Level) ->
    gs:rectangle(Canvas, [{fg, red}, {coords, [{X, Y}, {X + Size, Y + Size}]}]),
    draw_init(Canvas, {X, Y}, Size, 0, Level),
    draw_init(Canvas, {X + Size, Y}, Size, 90, Level),
    draw_init(Canvas, {X + Size, Y + Size}, Size, 180, Level),
    draw_init(Canvas, {X, Y + Size}, Size, 270, Level).

draw_init(Canvas, {X, Y}, Size, Angle, 0) ->
    % draw resulting curve
    draw_gen(Canvas, {X, Y}, Size, Angle);
draw_init(Canvas, {X, Y}, Size, Angle, Level) ->
    Step = Size / 4,
    
    % prepare absolute coords for each corner
    Coords = make_absolute_coords({X, Y}, rotate_coords(?RELATIVE_PATH(Step), Angle, {0, 0})),
    
    % mix absolute coord for each corner and corresponding angle
    CoordsAngles = lists:zip(Coords, [0 | ?ABSOLUTE_ANGLES]),
    
    % draw init figure at each corner according to angle
    Apply = fun({{Xi, Yi}, CornerAngle}) -> draw_init(Canvas, {Xi, Yi}, Step, Angle + CornerAngle, Level - 1) end,
    
    % remove last coord and apply draw_init to the resulting list
    lists:foreach(Apply, lists:reverse(tl(lists:reverse(CoordsAngles)))).

make_absolute_coords({X, Y}, RelCoords) ->
    make_absolute_coords({X, Y}, RelCoords, [{X, Y}]).
make_absolute_coords({_X, _Y}, [], Coords) ->
    lists:reverse(Coords);
make_absolute_coords({X, Y}, [{RelX, RelY} | Other], Coords) ->
    NewX = X + RelX,
    NewY = Y + RelY,
    make_absolute_coords({NewX, NewY}, Other, [{NewX, NewY} | Coords]).

%% rotates the point around X0, Y0
rotate_point({X, Y}, Angle, {X0, Y0}) ->
    X1 = X0 + (X - X0) * math:cos(Angle) - (Y - Y0) * math:sin(Angle),
    Y1 = Y0 + (X - X0) * math:sin(Angle) + (Y - Y0) * math:cos(Angle),
    {X1, Y1}.

rotate_coords([], _DegreeAngle, {_X0, _Y0}) -> [];
rotate_coords(Coords, DegreeAngle, {X0, Y0}) ->
    RadAngle = degree_to_radian(DegreeAngle),
    Rotate = fun({X, Y}) -> rotate_point({X, Y}, RadAngle, {X0, Y0}) end,
    lists:map(Rotate, Coords).

draw_gen(Canvas, {X, Y}, Size, Angle) ->
    Step = Size / 4,
    Coords = make_absolute_coords({X, Y}, rotate_coords(?RELATIVE_PATH(Step), Angle, {0, 0})),
    gs:line(Canvas, [{coords, Coords}]).

loop() ->
    receive
        _Other ->
            loop()
    end.

This snippet took 0.03 seconds to highlight.

Back to the Entry List or Home.

Delete this entry (admin only).