海龟作图
引言
turtle来源
Logo的原型来自另一个计算机语言LISP,派普特修改了LISP的语法使其更易于阅读。Logo常被称作没有括号的Lisp。
Logo是一种解释型语言,和其他语言不同的是,它内置一套海龟绘图(Turtle Graphics)系统,通过向海龟发送命令,用户可以直观地学习程序的运行过程,因此很适于儿童学习。它亦适合用作数学教学。
海龟绘图使得Logo用户可以通过简单的编程创作出丰富多彩的视觉效果或图案。假想一只带着画笔的海龟可以接受简单的命令,例如向前走100步,或者左转30度。通过对这只海龟发送命令,可以让它绘制出较为复杂的图形,例如正方形,三角形,圆等。
海龟的移动相对于它本身所在的位置。例如,命令"左90"意味着让海龟左转90度,学生可以站在海龟的角度来思考它将如何执行命令,这使得程序设计更加形象化,也更易于理解。 来自:wiki https://zh.wikipedia.org/wiki/Logo_(程序语言) python上直接有turtle的接口,而C++的turtle暂时还没有一个人官方的库。所以本次任务就是做一个初步的turtle接口
本次实现的功能
(1)设置海龟类型的基本操作为: void StartTurtleGraphics() //显示作图窗口,并在窗口内写出本人的姓名。 void StartTurtle() //令海龟处于作图的初始状态。即显示作图窗口,并将海龟定位在窗口正中; //置画笔状态为落笔、龟头朝向为0度(正东方向) void PenUp() //改变画笔状态为抬笔·从此时起,海龟移动将不在屏幕上作图。 void PenDown() //改变画笔状态为落笔。从此时起,海龟移动将在屏幕上作图。 int TurtleHeading() //返回海龟头当前朝向的角度。 aPoint * TurtlePos() //返回海龟的当前位置。 void Move(intsteps) //依照海龟头的当前朝向,向前移动海龟steps步. void Turn(intdegrees) //改变海龟头的当前朝向,逆时针旋转degrees度。 void MoveTTo(aPoint newPos) //将海龟移动到新的位置newPos。如果是落笔状态,则同时作图。 void TurnTTo(float angle) //改变海龟头的当前朝向为,从正东方向起的angle度。 void SetTurtleColor(intcolor) 设置海龟画笔的颜色为color 完成这些功能的建立,即可做出一个初步的turtle框架
具体实现
turtle.h
#pragma once
#include <graphics.h>
#include <iostream>
#include <conio.h>
#include <cstdio>
#include <string>
#include <easyx.h>
#include <cstdlib>
#include <cmath>
#include <graphics.h>
using namespace std
;
#define UP 0
#define DOWN 1
#define PI 3.14159
typedef int penState
;
typedef struct { float x
, y
; } aPoint
;
typedef struct {
double heading
;
penState pen
;
int color
;
aPoint Pos
;
} newTurtle
;
class turtle {
public:
void copy(turtle
& C
);
void StartTurtleGraphics();
void StartTurtle();
void PenUp();
void PenDown();
int TurtleHeading();
aPoint
* TurtlePos();
void Move(int steps
);
void Turn(double degrees
);
void MoveTTo(aPoint newPos
);
void TurnTTo(double angle
);
void SetTurtleColor(int color
);
private:
newTurtle A
;
};
turtle.cpp
#include "turtle.h"
void turtle
::StartTurtleGraphics() {
initgraph(880, 640);
wchar_t a
[]= L
"输入你的姓名: ";
outtext(a
);
wchar_t s
[10];
wcin
>> s
;
outtext(s
);
}
void turtle
::StartTurtle() {
A
.Pos
.x
= 440;
A
.Pos
.y
= 320;
A
.pen
= DOWN
;
A
.heading
= 0;
}
void turtle
::PenUp() {
A
.pen
= UP
;
}
void turtle
::PenDown() {
A
.pen
= DOWN
;
}
int turtle
::TurtleHeading() {
return A
.heading
;
}
aPoint
* turtle
::TurtlePos() {
aPoint
* apt
= new(aPoint
);
apt
->x
= A
.Pos
.x
;
apt
->y
= A
.Pos
.y
;
return apt
;
}
void turtle
::Move(int steps
) {
double x1
=A
.Pos
.x
;
double y1
=A
.Pos
.y
;
A
.Pos
.x
= x1
+ steps
* cos((A
.heading
/ 360) * 2 * PI
);
A
.Pos
.y
= y1
+ steps
* (-1) * sin((A
.heading
/ 360) * 2 * PI
);
}
void turtle
::Turn(double degrees
) {
A
.heading
+= degrees
;
while (A
.heading
> 0) {
A
.heading
-= 360;
}
}
void turtle
::MoveTTo(aPoint newPos
) {
if (A
.pen
== UP
) {
A
.Pos
.x
= newPos
.x
;
A
.Pos
.y
= newPos
.y
;
}
else if (A
.pen
== DOWN
) {
double x1
= A
.Pos
.x
;
double y1
= A
.Pos
.y
;
A
.Pos
.x
= newPos
.x
;
A
.Pos
.y
= newPos
.y
;
line(x1
, y1
, A
.Pos
.x
, A
.Pos
.y
);
}
}
void turtle
::TurnTTo(double angle
) {
A
.heading
= angle
;
}
void turtle
::SetTurtleColor(int color
) {
setlinecolor(color
);
}
void turtle
::copy(turtle
& C
) {
A
.color
= C
.A
.color
;
A
.heading
= C
.A
.heading
;
A
.pen
= C
.A
.pen
;
A
.Pos
.x
= C
.A
.Pos
.x
;
A
.Pos
.y
= C
.A
.Pos
.y
;
}
test.cpp
#include "turtle.h"
turtle B
;
void drawline(double length
) {
turtle C
;
C
.copy(B
);
C
.Move(length
);
aPoint
* newpos_1
;
newpos_1
= C
.TurtlePos();
aPoint newpos_2
;
newpos_2
.x
= newpos_1
->x
;
newpos_2
.y
= newpos_1
->y
;
B
.MoveTTo(newpos_2
);
}
void drawtangle(double length
,double width
) {
for (int i
= 0; i
< 2; i
++) {
drawline(length
);
B
.Turn(90);
drawline(width
);
B
.Turn(90);
}
}
void drawcircle(double r
) {
double k
= 2 * sin((1.0 / 360)*2.0*PI
) * r
;
cout
<< k
<< endl
;
for (int i
= 0; i
< 180; i
++) {
drawline(k
);
B
.Turn(2);
}
}
int main() {
B
.StartTurtleGraphics();
B
.StartTurtle();
B
.PenUp();
B
.SetTurtleColor(YELLOW
);
B
.PenDown();
drawline(200);
B
.Turn(30);
drawtangle(100, 100);
drawcircle(200);
aPoint pos
;
pos
.x
= 440;
pos
.y
= 320;
B
.MoveTTo(pos
);
drawcircle(200);
drawtangle(100, 100);
B
.PenUp();
drawtangle(100, 100);
while (!_kbhit()) {
;
}
closegraph();
return 0;
}
待优化,由于是使用line函数直接画线逼近圆,所以当半径较大时需要调整分割次数以使圆形较为圆润,而这需要一个度量标准,即当半径多大时分割次数为多少。 还有一点问题就是当分割次数过大时,sin过小,math提供的sin函数无法满足计算。所以画圆最为理想的解法应该为画点来做圆,感兴趣的话可以自己尝试一下用点法画圆
画圆算法(Bresenham + 中点)
文末
这个turtle框架还是很粗糙的,仅供参考,希望可以给一些萌新们一些思路上的启发。如果有什么疑问,可以在讨论区讨论。 另:如果有兴趣的话可以阅读python turtle模板,写一个自己的功能强大的C++ turtle。 github上关于各种语言的turtle有很多,感兴趣的话可以下载学习。
最后
相信很多看到这个blog的都是为了写作业。我就是为了写作业才开始了解turtle的,但是搜了很多blog都没有满意的,所以就干脆自己写一个。不要谢哦!!
没有将这篇文传到下载区,我简直就是良心创作者/dog. 不要吝惜一键三连,喝水不忘挖井人嘛!