part Ⅱ Turtle Graphics
Logo是麻省理工学院发明的一种编程语言,最初用于在太空中移动机器人。海龟图形,添加到Logo语言中,允许程序员向屏幕上的“海龟”发出一系列指令,并在其移动时画出一条线。海龟图形也被添加到许多不同的编程语言中,包括Python,它是标准库的一部分。
这次实验就是学着用turtle画一些图案,以及对图案进行一些角度计算。很简单,提供了两个函数,forward(units)和turn(degrees) ,forward(units)是指前进多少长度,turn(degrees)是指顺时针转多少度。
/**
* Draw a square.
*
* @param turtle
* the turtle context
* @param sideLength
* length of each side
*/
public static void drawSquare(Turtle turtle, int sideLength) {
int i = 0;
while (i < 4) {
i++;
turtle.forward(100);
turtle.turn(90);
}
}
画一个正方形很简单。
/**
* Determine inside angles of a regular polygon.
*
* There is a simple formula for calculating the inside angles of a polygon; you
* should derive it and use it here.
*
* @param sides
* number of sides, where sides must be > 2
* @return angle in degrees, where 0 <= angle < 360
*/
public static double calculateRegularPolygonAngle(int sides) {
return (sides - 2) * 180.0 / sides;
}
这个函数求一个正多边形的内角,也就是画一个正n边形时需要转的角度。很简单的数学公式
/**
* Determine number of sides given the size of interior angles of a regular
* polygon.
*
* There is a simple formula for this; you should derive it and use it here.
* Make sure you *properly round* the answer before you return it (see
* java.lang.Math). HINT: it is easier if you think about the exterior angles.
*
* @param angle
* size of interior angles in degrees, where 0 < angle < 180
* @return the integer number of sides
*/
public static int calculatePolygonSidesFromAngle(double angle) {
return (int) (360 / (180 - Math.round(angle)));
}
这个函数根据正n边形的一个内角计算他有多少边,利用外角和公式很容易求得。
/**
* Given the number of sides, draw a regular polygon.
*
* (0,0) is the lower-left corner of the polygon; use only right-hand turns to
* draw.
*
* @param turtle
* the turtle context
* @param sides
* number of sides of the polygon to draw
* @param sideLength
* length of each side
*/
public static void drawRegularPolygon(Turtle turtle, int sides, int sideLength) {
int i = 0;
while (i < sides) {
i++;
turtle.forward(sideLength);
turtle.turn(180 - /**
* Given the number of sides, draw a regular polygon.
*
* (0,0) is the lower-left corner of the polygon; use only right-hand turns to
* draw.
*
* @param turtle
* the turtle context
* @param sides
* number of sides of the polygon to draw
* @param sideLength
* length of each side
*/
public static void drawRegularPolygon(Turtle turtle, int sides, int sideLength) {
int i = 0;
while (i < sides) {
i++;
turtle.forward(sideLength);
turtle.turn(180 - calculateRegularPolygonAngle(sides));
}
}(sides));
}
}
这是画一个任意正n边形的函数,主要用刚才实现的calculateRegularPolygonAngle函数。
/**
* Given the current direction, current location, and a target location,
* calculate the heading towards the target point.
*
* The return value is the angle input to turn() that would point the turtle in
* the direction of the target point (targetX,targetY), given that the turtle is
* already at the point (currentX,currentY) and is facing at angle
* currentHeading. The angle must be expressed in degrees, where 0 <= angle <
* 360.
*
* @param currentHeading
* current direction as clockwise from north
* @param currentX
* current location x-coordinate
* @param currentY
* current location y-coordinate
* @param targetX
* target point x-coordinate
* @param targetY
* target point y-coordinate
* @return adjustment to heading (right turn amount) to get to target point,
* must be 0 <= angle < 360
*/
public static double calculateHeadingToPoint(double currentHeading, int currentX, int currentY, int targetX,
int targetY) {
return (270 - currentHeading - Math.atan2((currentY - targetY), (currentX - targetX)) * 180 / Math.PI) % 360;
}
这个函数实现的是,给定一个点的位置和它当前的前进方向,求到目标点需要转动的角度。这个在纸上验算验算就能找到一个通式。注意角度范围是(0,360),所以%360.
/**
* Given a sequence of points, calculate the heading adjustments needed to get
* from each point to the next.
*
* Assumes that the turtle starts at the first point given, facing up (i.e. 0
* degrees). For each subsequent point, assumes that the turtle is still facing
* in the direction it was facing when it moved to the previous point. You
* should use calculateHeadingToPoint() to implement this function.
*
* @param xCoords
* list of x-coordinates (must be same length as yCoords)
* @param yCoords
* list of y-coordinates (must be same length as xCoords)
* @return list of heading adjustments between points, of size 0 if (# of
* points) == 0, otherwise of size (# of points) - 1
*/
public static List<Double> calculateHeadings(List<Integer> xCoords, List<Integer> yCoords) {
List<Double> list = new ArrayList<>();
int N = xCoords.size();
double face = 0;
int i = 0;
while (i < N - 1) {
double k = calculateHeadingToPoint(face, xCoords.get(i), yCoords.get(i), xCoords.get(i + 1),
yCoords.get(i + 1));
list.add(k);
face = (face + k) % 360;
i++;
}
System.out.println(list);
return list;
}
这个函数是上一个函数的升级,要计算一系列点转动的角度和,只是重复利用calculateHeadingToPoint函数求和。