The following is the web exercise 3.2.12. from the book Computer Science An Interdisciplinary Approach by Sedgewick & Wayne:
Write a program that draws a vector field. A vector field associates a vector with every point in a Euclidean space. Widely used in physics to model speed and direction of a moving object or strength and direction of a Newtonian force.
Here is my program:
public class Vector {
private final double[] coordinates;
public Vector(double[] coordinates) {
this.coordinates = coordinates;
}
private int getCoordinatesLength() {
return coordinates.length;
}
public double getCoordinate(int index) {
return coordinates[index - 1];
}
public double getLength() {
double sumOfCoordinatesSquared = 0;
for (int i = 0; i < getCoordinatesLength(); i++) {
sumOfCoordinatesSquared += getCoordinate(i + 1) * getCoordinate(i + 1);
}
return Math.sqrt(sumOfCoordinatesSquared);
}
private double getDirection2D() {
return Math.atan(getCoordinate(2) / getCoordinate(1));
}
public double[] getDirection() {
if (getCoordinatesLength() != 2 && getCoordinatesLength() != 3) {
throw new IllegalArgumentException("dimention of the vector must be either 2 or 3");
}
int dimention = 0;
if (getCoordinatesLength() == 2) dimention = 1;
else if (getCoordinatesLength() == 3) dimention = 2;
double[] angles = new double[dimention];
if (getCoordinatesLength() == 2) {
angles[0] = Math.atan(getCoordinate(2) / getCoordinate(1));
} else if (getCoordinatesLength() == 3) {
double vectorLength = getLength();
double azimuth = Math.atan(getCoordinate(2) / getCoordinate(1));
double zenith = Math.acos(getCoordinate(3) / vectorLength);
angles[0] = azimuth;
angles[1] = zenith;
}
return angles;
}
public Vector add(Vector otherVector) {
if (getCoordinatesLength() != otherVector.getCoordinatesLength()) {
throw new IllegalArgumentException("length of the vectors must be equal");
}
double[] newCoordinates = new double[getCoordinatesLength()];
for (int i = 0; i < getCoordinatesLength(); i++) {
newCoordinates[i] = getCoordinate(i + 1) + otherVector.getCoordinate(i + 1);
}
return new Vector(newCoordinates);
}
public Vector multiplyByScalar(double scalar) {
double[] newCoordinates = new double[getCoordinatesLength()];
for (int i = 0; i < getCoordinatesLength(); i++) {
newCoordinates[i] = getCoordinate(i + 1) * scalar;
}
return new Vector(newCoordinates);
}
public Vector subtract(Vector otherVector) {
return add(otherVector.multiplyByScalar(-1.0));
}
public boolean isEqual(Vector otherVector) {
if (getCoordinatesLength() != otherVector.getCoordinatesLength()) return false;
for (int i = 0; i < getCoordinatesLength(); i++) {
if (getCoordinate(i + 1) != otherVector.getCoordinate(i + 1)) return false;
}
return true;
}
public double applyDotProduct(Vector otherVector) {
if (getCoordinatesLength() != otherVector.getCoordinatesLength()) {
throw new IllegalArgumentException("length of the vectors must be equal");
}
double dotProduct = 0;
for (int i = 0; i < getCoordinatesLength(); i++) {
dotProduct += getCoordinate(i + 1) * otherVector.getCoordinate(i + 1);
}
return dotProduct;
}
public Vector applyCrossProduct(Vector otherVector) {
if (getCoordinatesLength() != otherVector.getCoordinatesLength()) {
throw new IllegalArgumentException("length of the vectors must be equal");
}
if (getCoordinatesLength() != 3) {
throw new IllegalArgumentException("dimention of the vector must be 3");
}
int x = 1;
int y = 2;
int z = 3;
double newXCoordinate = getCoordinate(y) * otherVector.getCoordinate(z) - getCoordinate(z) * otherVector.getCoordinate(y);
double newYCoordinate = getCoordinate(z) * otherVector.getCoordinate(x) - getCoordinate(x) * otherVector.getCoordinate(z);
double newZCoordinate = getCoordinate(x) * otherVector.getCoordinate(y) - getCoordinate(y) * otherVector.getCoordinate(x);
double[] newCoordinates = {
newXCoordinate,
newYCoordinate,
newZCoordinate
};
return new Vector(newCoordinates);
}
public boolean isPerpendicular(Vector otherVector) {
if (applyDotProduct(otherVector) == 0) return true;
else return false;
}
public boolean isParallel(Vector otherVector) {
double scalingFactor = 0;
for (int i = 0; i < getCoordinatesLength(); i++) {
if (getCoordinate(i + 1) != 0 && otherVector.getCoordinate(i + 1) != 0) {
scalingFactor = getCoordinate(i + 1) / otherVector.getCoordinate(i + 1);
break;
}
}
double[] newCoordinates = new double[getCoordinatesLength()];
for (int i = 0; i < getCoordinatesLength(); i++) {
newCoordinates[i] = getCoordinate(i + 1) / scalingFactor;
}
Vector newVector = new Vector(newCoordinates);
if (otherVector.isEqual(newVector)) return true;
else return false;
}
public String toString() {
String printedCoordinates = "";
for (int i = 0; i < getCoordinatesLength() - 1; i++) {
printedCoordinates += (getCoordinate(i + 1) + ", ");
}
return "[" + printedCoordinates + getCoordinate(getCoordinatesLength()) + "]";
}
public void draw(double originX, double originY, double scaleDownFactor, double arrowHeadSize) {
if (getCoordinatesLength() != 2) {
throw new IllegalArgumentException("dimention of the vector must be 3");
}
double newX = getCoordinate(1) * scaleDownFactor;
double newY = getCoordinate(2) * scaleDownFactor;
double arrowHeadPointX = originX + newX;
double arrowHeadPointY = originY + newY;
StdDraw.line(originX, originY, arrowHeadPointX, arrowHeadPointY);
double arrowHeadBaseX = arrowHeadSize * Math.sin(getDirection2D());
double arrowHeadBaseY = arrowHeadSize * Math.cos(getDirection2D());
double[] arrowHeadXCoordinates = {-arrowHeadBaseX + (originX + 0.95 * newX),
arrowHeadBaseX + (originX + 0.95 * newX),
arrowHeadPointX
};
double[] arrowHeadYCoordinates = {
arrowHeadBaseY + (originY + 0.95 * newY),
-arrowHeadBaseY + (originY + 0.95 * newY),
arrowHeadPointY
};
StdDraw.filledPolygon(arrowHeadXCoordinates, arrowHeadYCoordinates);
}
public static void main(String[] args) {
/*
double[] coordinatesOfVectorA = {1,2};
double[] coordinatesOfVectorB = {0,1};
Vector vectorA = new Vector(coordinatesOfVectorA);
Vector vectorB = new Vector(coordinatesOfVectorB);
double originX = 0.5;
double originY = 0.5;
double scaleDownFactor = 0.1;
double arrowHeadSize = 0.01;
System.out.println("Vector A = " + vectorA.toString());
System.out.println("Vector B = " + vectorB.toString());
System.out.println("A plus B equals " + vectorA.add(vectorB).toString());
System.out.println("A minus B equals " + vectorA.subtract(vectorB).toString());
System.out.println("Dot product of A and B equals " + vectorA.applyDotProduct(vectorB));
//System.out.println("Cross product of A and B equals " + vectorA.applyCrossProduct(vectorB).toString());
System.out.println(vectorA.isParallel(vectorB));
vectorA.draw(originX, originY, scaleDownFactor, arrowHeadSize);
vectorB.draw(originX, originY, scaleDownFactor, arrowHeadSize);
*/
StdDraw.setXscale(-1, 1);
StdDraw.setYscale(-1, 1);
for (int i = -10; i < 11; i++) {
for (int j = -10; j < 11; j++) {
if (i == 0 && j == 0) j++;
double x = 1.0 * i / 10;
double y = 1.0 * j / 10;
double vectorXCoordinate = -y;
double vectorYCoordinate = x;
double[] coordinates = {
vectorXCoordinate,
vectorYCoordinate
};
Vector vector = new Vector(coordinates);
vector.draw(x, y, 0.1, 0.01);
}
}
}
}
StdDraw is a simple API written by the authors of the book. I checked my program and it works. Here is one instance of it:
Input (taken from here):
Output:
Is there any way that I can improve my program?
Thanks for your attention.