turtle(海龟作图),C++版「建议收藏」

turtle(海龟作图),C++版「建议收藏」海龟作图引言turtle来源Logo的原型来自另一个计算机语言LISP,派普特修改了LISP的语法使其更易于阅读。Logo常被称作没有括号的Lisp。Logo是一种解释型语言,和其他语言不同的是,它内置一套海龟绘图(TurtleGraphics)系统,通过向海龟发送命令,用户可以直观地学习程序的运行过程,因此很适于儿童学习。它亦适合用作数学教学。海龟绘图使得Logo用户可以通过简单的编程创作出丰富多彩的视觉效果或图案。假想一只带着画笔的海龟可以接受简单的命令,例如向前走100步,或者左转30度。

大家好,又见面了,我是你们的朋友全栈君。

海龟作图

引言

turtle来源

Logo的原型来自另一个计算机语言LISP,派普特修改了LISP的语法使其更易于阅读。Logo常被称作没有括号的Lisp。

Logo是一种解释型语言,和其他语言不同的是,它内置一套海龟绘图(Turtle Graphics)系统,通过向海龟发送命令,用户可以直观地学习程序的运行过程,因此很适于儿童学习。它亦适合用作数学教学。

海龟绘图使得Logo用户可以通过简单的编程创作出丰富多彩的视觉效果或图案。假想一只带着画笔的海龟可以接受简单的命令,例如向前走100步,或者左转30度。通过对这只海龟发送命令,可以让它绘制出较为复杂的图形,例如正方形,三角形,圆等。

海龟的移动相对于它本身所在的位置。例如,命令”左90″意味着让海龟左转90度,学生可以站在海龟的角度来思考它将如何执行命令,这使得程序设计更加形象化,也更易于理解。
来自:wiki
https://zh.wikipedia.org/wiki/Logo_(%E7%A8%8B%E5%BA%8F%E8%AF%AD%E8%A8%80)
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;        //取值UP或DOWN
typedef struct { 
    float x, y; } aPoint; //位置
typedef struct { 
   
	double heading;	//海龟头方向
	penState pen; //画笔状态
    int color;	//画笔当前颜色
	aPoint Pos; //海龟当前位置
} newTurtle;
class turtle { 
   
	public:
		//复制turtle类中的数据到另一个类中
		void copy(turtle& C);


		//显示作图窗口,并在窗口内写出本人的姓名。
		void StartTurtleGraphics();
		//令海龟处于作图的初始状态。即显示作图窗口,并将海龟定位在窗口正中;
		//置画笔状态为落笔、龟头朝向为0度(正东方向)
		void StartTurtle();
		//改变画笔状态为抬笔·从此时起,海龟移动将不在屏幕上作图。
		void PenUp();
		//改变画笔状态为落笔。从此时起,海龟移动将在屏幕上作图。
		void PenDown();
		//返回海龟头当前朝向的角度。
		int TurtleHeading();
		//返回海龟的当前位置。
		aPoint* TurtlePos();
		//依照海龟头的当前朝向,向前移动海龟steps步.
		void Move(int steps);
		//改变海龟头的当前朝向,逆时针旋转degrees度。
		void Turn(double degrees);
		//将海龟移动到新的位置newPos。如果是落笔状态,则同时作图。
		void MoveTTo(aPoint newPos);
		//改变海龟头的当前朝向为,从正东方向起的angle度。
		void TurnTTo(double angle);
		//设置海龟画笔的颜色为color
		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);
}

//令海龟处于作图的初始状态。即显示作图窗口,并将海龟定位在窗口正中;
//置画笔状态为落笔、龟头朝向为0度(正东方向)
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;
}

//依照海龟头的当前朝向,向前移动海龟steps步.
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);
}
//改变海龟头的当前朝向,逆时针旋转degrees度。
void turtle::Turn(double degrees) { 
   
	A.heading += degrees;
	while (A.heading > 0) { 
   
		A.heading -= 360;
	}
}
//将海龟移动到新的位置newPos。如果是落笔状态,则同时作图。
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);
	}
}
//改变海龟头的当前朝向为,从正东方向起的angle度。
void turtle::TurnTTo(double angle) { 
   
	A.heading = angle;
}
//设置海龟画笔的颜色为color
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);

}
//以乌龟当前点出发,调用drawline(),画矩形
void drawtangle(double length,double width) { 
   
	for (int i = 0; i < 2; i++) { 
   
		drawline(length);
		B.Turn(90);
		drawline(width);
		B.Turn(90);
	}
}
//以乌龟当前点出发,调用drawline(),画圆
//由于圆形只能不断逼近,所以本次采用180次分割,使肉眼见图形为圆形
//将圆分成180份,运用三角函数计算每一段的段长为2*sin(1)*r
//待优化,由于是使用line函数直接画线逼近圆,所以当半径较大时需要调整分割次数以使圆形较为圆润
//而这需要一个度量标准,即当半径多大时分割次数为多少
//还有一点问题就是当分割次数过大时,sin过小,math提供的sin函数无法满足计算
//所以画圆最为理想的解法应该为画点来做圆
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);
	}
}
//test函数,试验海龟作图及相关函数是否正确
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.
不要吝惜一键三连,喝水不忘挖井人嘛!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/154095.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长

相关推荐

  • 快排的优化方法(优化营商环境方案)

    聚集相同元素排序是快速排序的一种优化方案,它的思路是在经过一次找基准之后把数据中与基准相同的数据聚集到基准左右,这样就可以少进行几次递归找基准的过程,从而提高了运行效率。看以下程序:importjava.util.Arrays;publicclassFocusAlikeQuickSort{/**找基准的方法,与前文相同*/publicstatic…

    2022年4月11日
  • Arcgis api for JavaScript下载及部署(IIS和Tomcat)

    Arcgis api for JavaScript下载及部署(IIS和Tomcat)目录一,各版本下载地址二,ArcGISAPIForJavaScript3.17本地部署(IIS)2.1修改相应的js文件(2个文件)2.2将修改好的函数库复制到指定位置2.3测试ArcGISAPIForJavaScript函数库是否安装成功三,Tomcat部署3.1修改2个js文件3.2将修改好的函数库复制到指定位置3.3测试ArcGI…

    2022年6月3日
  • 华为手机像素密度排行_「屏幕像素密度」(全解析)屏幕尺寸,分辨率,像素,PPI之间到底什么关系? – seo实验室…[通俗易懂]

    华为手机像素密度排行_「屏幕像素密度」(全解析)屏幕尺寸,分辨率,像素,PPI之间到底什么关系? – seo实验室…[通俗易懂]屏幕像素密度今天我给大家来讲讲这几个咱们经常打交道的词到底啥意思,以及他们之间到底有什么关系。这篇文章是我花了一个下午从N多篇文章里提炼出的一个白话版,保证让你看得懂。咱们从手机开始说起吧。先上一张图,给大家看看关于手机屏幕方面的一些参数。红框内的三个参数,大家一定都不陌生,我也不陌生。不过讲真的,就在不久前,我连手机的屏幕尺寸到底是怎么算出来的都不知道。下面我们开始慢慢讲。屏幕(主屏)尺寸是什么…

    2022年6月9日
  • 【Python矩阵转置】| 试使用多方法实现[通俗易懂]

    【Python矩阵转置】| 试使用多方法实现[通俗易懂]矩阵的重要性:实际存储数据通常包含有特征根或是特征向量,是重要。借助Python实现矩阵运算不可或缺。在此过程中,矩阵的转置至关重要。下为几种常见的矩阵转置方法:方法一:(直接法)#step1:#初始化原始矩阵matrix=[[1,2,3,4],[5,6,7,8],[9,10,11,12]]#通过函数指出矩阵的行与列row=len(matrix)col=len(matrix[0])#step2:#交换矩阵的行与列ROW=

    2022年5月5日
  • eclipse的创建java程序步骤

    eclipse的创建java程序步骤众所周知,java是一个比较折腾的语言==当然这个折腾更多在软件上,在你好不容易在一大堆英文中下到jdk以及合适的idea或者eclipse合适版本,然后辛辛苦苦配置好的系统变量以后,打开界面以为新建就好了?那不可能,打开新建的时候你一定是崩溃的下面我们一起来看看如何在eclipse建立一个合适的项目包来开开心心的写helloworld吧!1.打开新建点击”包“输入一个包名这里尽量用规范的命名,这里我们给一个Test2.然后出来个界面你以为就可以开始写我们的helloworld了吗?

    2022年7月9日
  • 面向对象程序设计的基本原理_面向对象程序设计c++答案

    面向对象程序设计的基本原理_面向对象程序设计c++答案Java程序设计(面向对象)- 设计原理

    2022年4月22日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号