#define TURTLE_SIZE 4 #define TURTLE_SPEED_STEP 2 #define ANGLES 35 F64 angles[ANGLES] = { -2 * pi / 1, -2 * pi / 2, -2 * pi / 3, -2 * pi / 4, -2 * pi / 5, -2 * pi / 6, -2 * pi / 8, -2 * pi / 9, -2 * pi / 10, -2 * pi / 12, -2 * pi / 15, -2 * pi / 18, -2 * pi / 20, -2 * pi / 24, -2 * pi / 30, -2 * pi / 36, -2 * pi / 40, 0, 2 * pi / 40, 2 * pi / 36, 2 * pi / 30, 2 * pi / 24, 2 * pi / 20, 2 * pi / 18, 2 * pi / 15, 2 * pi / 12, 2 * pi / 10, 2 * pi / 9, 2 * pi / 8, 2 * pi / 6, 2 * pi / 5, 2 * pi / 4, 2 * pi / 3, 2 * pi / 2, 2 * pi / 1 }; class Turtle { F64 x, y, z, speed, theta, w; I64 dtheta_idx; CColorROPU16 edge, middle; Bool ends, first; } tt; U0 TurtlePlot(CDC *dc, Turtle *t, CColorROPU16 edge, CColorROPU16 middle) { F64 w = t->w / 2.0 - 1; if (w < 0) w = 0; dc->color = middle; GrLine3(dc, t->x + w * Cos(t->theta + pi / 2), t->y + w * Sin(t->theta + pi / 2), t->z, t->x + w * Cos(t->theta - pi / 2), t->y + w * Sin(t->theta - pi / 2), t->z); w = t->w / 2.0; dc->color = edge; GrPlot3(dc, t->x + w * Cos(t->theta + pi / 2), t->y + w * Sin(t->theta + pi / 2), t->z); GrPlot3(dc, t->x + w * Cos(t->theta - pi / 2), t->y + w * Sin(t->theta - pi / 2), t->z); } U0 TurtleMicroMove(Turtle *t, F64 dt) { t->x += dt * t->speed * Cos(t->theta); t->y += dt * t->speed * Sin(t->theta); t->theta = Wrap(t->theta + dt * angles[t->dtheta_idx]); } U0 TurtleEnd(CDC *dc, Turtle *t, CColorROPU16 edge, CColorROPU16 middle, F64 theta) { F64 r, x, y2; Turtle t2; if (r = t->w) { MemCopy(&t2, t, sizeof(Turtle)); //Save x = 0; while (TRUE) { t->x += 1 / r *Cos(theta); t->y += 1 / r * Sin(theta); x += 1 / r; y2 = r * r - 4 * x * x; if (y2 >= 0) { t->w = Sqrt(y2); TurtlePlot(dc, t, edge, middle); } else break; } MemCopy(t, &t2, sizeof(Turtle)); } } U0 TurtleMove(CDC *dc, Turtle *t, CColorROPU16 edge, CColorROPU16 middle) { I64 i, l = 16 * AbsI64(t->w + 1) * AbsI64(t->speed + 1); if (t->ends && t->first) TurtleEnd(dc, t, edge, middle, t->theta + pi); t->first = FALSE; for (i = 0; i < l; i++) { TurtleMicroMove(t, 1.0 / l); TurtlePlot(dc, t, edge, middle); } if (t->ends) TurtleEnd(dc, t, edge, middle, t->theta); } U0 TurtleInit(Turtle *t) { MemSet(t, 0, sizeof(Turtle)); t->x = Fs->pix_width >> 1; t->y = Fs->pix_height >> 1; t->z = 5; t->edge = BLACK; t->middle = YELLOW; t->dtheta_idx = ANGLES / 2; t->first = TRUE; t->ends = TRUE; } U0 DrawIt(CTask *, CDC *dc) { Turtle t2; MemCopy(&t2, &tt, sizeof(Turtle)); GrPrint(dc, 0, 0, "Layer:%f Speed:%f theta:%5.1f dtheta:%5.1f Width:%f", tt.z, tt.speed, tt.theta * 180 / pi, angles[tt.dtheta_idx] * 180 / pi, tt.w); TurtleMove(dc, &t2, RED, LTRED); dc->color = LTRED; GrLine(dc, t2.x + TURTLE_SIZE * Cos(t2.theta + pi / 2), t2.y + TURTLE_SIZE * Sin(t2.theta + pi / 2), t2.x + TURTLE_SIZE * Cos(t2.theta - pi / 2), t2.y + TURTLE_SIZE * Sin(t2.theta - pi / 2)); GrLine(dc, t2.x + TURTLE_SIZE * Cos(t2.theta + pi / 2), t2.y + TURTLE_SIZE * Sin(t2.theta + pi / 2), t2.x + TURTLE_SIZE * Cos(t2.theta), t2.y + TURTLE_SIZE * Sin(t2.theta)); GrLine(dc, t2.x + TURTLE_SIZE * Cos(t2.theta - pi / 2), t2.y + TURTLE_SIZE * Sin(t2.theta - pi / 2), t2.x + TURTLE_SIZE * Cos(t2.theta), t2.y + TURTLE_SIZE * Sin(t2.theta)); } U0 SetMenu() { I64 i; U8 buf[STR_LEN]; CMenuEntry *tmpse; for (i = 0; i <= 9; i++) { StrPrint(buf, "Settings/Layer%d", i); if (tmpse = MenuEntryFind(Fs->cur_menu, buf)) { if (i == tt.z) tmpse->checked = TRUE; else tmpse->checked = FALSE; } } if (tmpse = MenuEntryFind(Fs->cur_menu, "Settings/Ends")) { if (tt.ends) tmpse->checked = TRUE; else tmpse->checked = FALSE; } } U0 Lattice() { Bool aim = FALSE; I64 arg1, arg2; CDC *dc = DCAlias; DCDepthBufAlloc(dc); MenuPush( "File {" " Abort(,CH_SHIFT_ESC);" " Exit(,CH_ESC);" "}" "Play {" " Restart(,'\n');" " Step(,CH_SPACE);" " Accelerator(,,SC_CURSOR_UP);" " Break(,,SC_CURSOR_DOWN);" " Left(,,SC_CURSOR_LEFT);" " Right(,,SC_CURSOR_RIGHT);" "}" "Settings {" " Color(,'c');" " Wider(,'+');" " Narrower(,'-');" " Ends(,'e');" " Layer0(,'0');" " Layer1(,'1');" " Layer2(,'2');" " Layer3(,'3');" " Layer4(,'4');" " Layer5(,'5');" " Layer6(,'6');" " Layer7(,'7');" " Layer8(,'8');" " Layer9(,'9');" "}" ); SettingsPush; //See SettingsPush AutoComplete; WinBorder; WinMax; DocCursor; DocClear; TurtleInit(&tt); SetMenu; Fs->win_inhibit = WIG_TASK_DEFAULT - WIF_FOCUS_TASK_MENU - WIF_SELF_FOCUS - WIF_SELF_GRAB_SCROLL; Fs->draw_it = &DrawIt; try { while (TRUE) { switch (MessageGet(&arg1, &arg2, 1 << MESSAGE_KEY_DOWN | 1 << MESSAGE_MS_L_DOWN| 1 << MESSAGE_MS_R_DOWN | 1 << MESSAGE_MS_R_UP | 1 << MESSAGE_MS_MOVE)) { case MESSAGE_MS_L_DOWN: tt.first = TRUE; tt.x = arg1; tt.y = arg2; break; case MESSAGE_MS_R_DOWN: aim = TRUE; tt.theta = Arg(arg1 - tt.x, arg2 - tt.y); break; case MESSAGE_MS_MOVE: if (aim) tt.theta = Arg(arg1 - tt.x, arg2 - tt.y); break; case MESSAGE_MS_R_UP: tt.theta = Arg(arg1 - tt.x, arg2 - tt.y); aim = FALSE; break; case MESSAGE_KEY_DOWN: switch (arg1) { case 0: switch (arg2.u8[0]) { case SC_CURSOR_LEFT: if (tt.dtheta_idx) tt.dtheta_idx--; break; case SC_CURSOR_RIGHT: if (tt.dtheta_idx < ANGLES - 1) tt.dtheta_idx++; break; case SC_CURSOR_UP: tt.speed += TURTLE_SPEED_STEP; break; case SC_CURSOR_DOWN: if (tt.speed >= TURTLE_SPEED_STEP) tt.speed -= TURTLE_SPEED_STEP; break; } break; case '0'...'9': tt.z = arg1 - '0'; SetMenu; break; case 'c': tt.middle = PopUpColor("Mid Color\n\n"); tt.edge = PopUpColor("Edge Color\n\n"); break; case 'e': tt.ends = !tt.ends; break; case '+': tt.w++; break; case '-': if (tt.w) tt.w--; break; case '\n': DCFill(dc); TurtleInit(&tt); SetMenu; break; case CH_ESC: case CH_SHIFT_ESC: goto lt_done; case CH_SPACE: TurtleMove(dc, &tt, tt.edge, tt.middle); break; } } } lt_done: MessageGet(,, 1 << MESSAGE_KEY_UP); } catch PutExcept; SettingsPop; DCFill(dc); DCDel(dc); MenuPop; } Lattice;