This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 2 years ago.
I have this problem where I am supposed to write this program where using a Point class to create points, then create a Rectangle class with methods like area,perimeter, and pointInside... My code is always resulting in a Null Pointer Exception and I don't know why.
class Point {
int x, y;
Point() {
x = y = 0;
}
Point(int x0, int y0) {
x = x0;
y = y0;
}
public String toString() {
return "(" + x + "," + y + ")";
}
}
class Rectangle {
Point p1,p2;
Rectangle(int x1,int y1,int x2,int y2)
{
x1 = p1.x;
y1 = p1.y;
x2 = p2.x;
y2 = p2.y;
}
Rectangle(Point p1,Point p2)
{
this.p1 = p1;
this.p2 = p2;
}
public int area ()
{
int width = p2.x - p1.x;
int height = p2.y - p1.y;
int area = width * height;
return area;
}
public int perimeter()
{
int side1 = p2.x - p1.x;
int side2 = p2.y - p1.y;
int perimeter = side1 + side2 + side1 + side2;
return perimeter;
}
public boolean pointInside(Point p)
{
if ((p.x >= p1.x && p.x <= p2.x) && (p.y >= p1.y && p.y <= p2.y))
{
return true;
} else {
return false;
}
}
}
class TestRectangle {
public static void main(String[] args) {
Point a = new Point(1,1);
Point b = new Point(2,2);
Point c = new Point(3,4);
Point d = new Point(8,2);
Rectangle yellow = new Rectangle(a, c);
Rectangle orange = new Rectangle(2, 3, 9, 6);
Rectangle green = new Rectangle(3, 4, 4, 5);
Rectangle blue = new Rectangle(5, 1, 6, 5);
Rectangle red = new Rectangle(7, 3, 9, 5);
System.out.println("Perimeter of the yellow rectangle = " + yellow.perimeter()); // 10
System.out.println("Perimeter of the orange rectangle= " + orange.perimeter()); // 20
System.out.println("Area of the yellow rectangle = " + yellow.area()); // 6
System.out.println("Area of the orange rectangle = " + orange.area()); // 21
System.out.println("Point B inside yellow? " + yellow.pointInside(b)); // true
System.out.println("Point D inside yello? " + yellow.pointInside(d)); // false
}
}
When something calls this constructor
Rectangle(int x1,int y1,int x2,int y2)
{
x1 = p1.x;
y1 = p1.y;
x2 = p2.x;
y2 = p2.y;
}
your variables p1 and p2 haven't been initialized to anything, since before that, all you do is declare those two fields, not actually set them to anything. They are null by default.
What you need to do is
Rectangle(int x1, int y1, int x2, int y2) {
p1 = new Point(x1, y1);
p2 = new Point(x2, y2);
}
I also have no idea why you're modifying the arguments to the constructor in the original.
Related
The user inputs 3 space separated coordinates that can make up a rectangle in the xy-plane. The algorithm returns what must be the 4th point to form a rectangle.
Example: "5 5", "5 7", and "7 5", newline separated, should return "7 7".
The below algorithm works for the provided test cases, but I am failing other cases, and I can't figure out why. Can anyone suggest a way to make my algorithm include all possible inputs - assuming that the 3 inputs provided do in fact form 3 corners of a rectangle?
import java.io.*;
public class cetvrta {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String point1 = reader.readLine(); // 5 5
String point2 = reader.readLine(); // 5 7
String point3 = reader.readLine(); // 7 5
String[] cord1 = point1.split(" "); // ["5","5"]
String[] cord2 = point2.split(" "); // ["5", "7"]
String[] cord3 = point3.split(" "); // ["7", "5"]
int x4 = 0;
int y4 = 0;
int x1 = Integer.parseInt(cord1[0]); // 5
int y1 = Integer.parseInt(cord1[1]); // 5
int x2 = Integer.parseInt(cord2[0]);
int y2 = Integer.parseInt(cord2[1]);
int x3 = Integer.parseInt(cord3[0]);
int y3 = Integer.parseInt(cord3[1]);
if (y1 == y2) {
if (x3 == x1) {
x4 = x2;
y4 = y3;
}
if (x3 == x2) {
x4 = x1;
y4 = y3;
}
}
if (y3 == y2) {
if (x2 == x3) {
x4 = x1;
y4 = y2;
}
if (x2 == x1) {
x4 = x3;
y4 = y2;
}
}
if (y1 == y3) {
if (x2 == x1) {
x4 = x3;
y4 = y2;
}
if (x2 == x3) {
x4 = x1;
y4 = y2;
}
}
System.out.println(x4 + " " + y4);
}
}
There is no hard and fast rule that "x-coordinates of 2 points of a rectangle has to match and so do the y-coordinates". Consider the image below for better understanding.
We can see that no two points have same x and y coordinates although there exists a perfect rectangle:
Fix:
I would recommend you to slightly change the algorithm as to proceed in the following way. Given the three points, find the point that isn't the corner(the one that does not pass through diagonal based out of other 2 points). From this point, calculate the slope to remaining points and assuming the 4th corner to be (x,y); draw out 2 locii. to satisfy slope1 * slope 2=-1. These 2 locii solved together will give the 4th point.
This is weird, rethink that:
if (y3 == y2) {
if (x2 == x3) { // <---
x4 = x1; // <---
y4 = y2; // <---
}
if (x2 == x1) {
x4 = x3;
y4 = y2; // <---
}
}
It would be better to use basic vector algebra to resolve this task:
calculate vectors between the three known points
define which point of the given three is a vertex of right angle (90°) - if any
this can be done using the fact that the scalar product of two perpendicular vectors is 0: v1.x * v2.x + v1.y * v2.0 == 0
find the fourth point by adding to the right angle vertex two vectors outgoing from this vertex to the other two known points.
Sample implementation could look like this:
// auxiliary classes
class Point {
int x, y;
Point(int x, int y) {
this.x = x;
this.y = y;
}
Point add(Vector v) {
return new Point(this.x + v.x, this.y + v.y);
}
#Override
public String toString() {
return String.format("(%d, %d)", x, y);
}
}
class Vector {
int x, y;
Vector(int x, int y) {
this.x = x;
this.y = y;
}
Vector(Point p1, Point p2) {
this(p2.x - p1.x, p2.y - p1.y);
}
static boolean isRightAngle(Vector v1, Vector v2) {
return 0 == (v1.x * v2.x + v1.y * v2.y);
}
Vector add(Vector v) {
return new Vector(this.x + v.x, this.y + v.y);
}
}
Method to find the right angle vertex:
static int rightAngleVertexIndex(Point ... p) {
assert p.length == 3;
Vector v01 = new Vector(p[0], p[1]);
Vector v12 = new Vector(p[1], p[2]);
Vector v20 = new Vector(p[2], p[0]);
if (Vector.isRightAngle(v01, v12)) {
return 1;
} else if (Vector.isRightAngle(v12, v20)) {
return 2;
} else if (Vector.isRightAngle(v20, v01)) {
return 0;
} else {
return -1;
}
}
Method to find the 4th point of rectangle (return null if no rectangle is possible):
static Point findFourthVertex(Point ... points) {
assert points.length == 3;
final int[][] otherVertices = {
{1, 2},
{0, 2},
{0, 1},
};
Point result = null;
int rightAngleIx = rightAngleVertexIndex(points);
if (rightAngleIx != -1) {
Point rightAngle = points[rightAngleIx];
Point p1 = points[otherVertices[rightAngleIx][0]];
Point p2 = points[otherVertices[rightAngleIx][1]];
result = rightAngle.add(new Vector(rightAngle, p1).add(new Vector(rightAngle, p2)));
System.out.println("The fourth vertex of the rectangle: " + result);
} else {
System.out.println("No right angle found between any of the points " + Arrays.toString(points));
}
return result;
}
Test:
findFourthVertex(new Point(1, 1), new Point(5, 1), new Point(1, 4));
findFourthVertex(new Point(-1, -1), new Point(5, 0), new Point(6, 5));
Output:
The fourth vertex of the rectangle: (5, 4)
No right angle found between any of the points [(-1, -1), (5, 0), (6, 5)]
I have a class that manages translating from screen co-ordinates to image co-ordinates.
However, I have an "off by one error".
The following gives 318, 198, instead of 319, 199:
#Test
public void test6rightScreenCornerToImageCoOrdAfterZoomingAndScaling() {
PointTranslation pointTranslation = new PointTranslation();
pointTranslation.setOriginalSize(0, 0, 320, 200); // original image
pointTranslation.zoomIn(9, 9, 310, 190); // zoomed image starting at 9,9
pointTranslation.scale(0, 0, 800, 800);
Point translatedPoint = pointTranslation.transformPoint(799,799);
System.out.println(testName.getMethodName() + " : " + translatedPoint.toString());
assertTrue(translatedPoint.x == 319);
assertTrue(translatedPoint.y == 199);
}
=============================================================
Full Listing:
package gtx;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.internal.gdip.PointF;
import org.eclipse.swt.internal.gdip.RectF;
#SuppressWarnings("restriction")
public class PointTranslation {
RectF originalSize = null;
RectF currentSize = null;
RectF scaledSize = null;
public void setOriginalSize(int originX, int originY, int width, int height) {
originalSize = getRectangle(originX, originY, width, height);
currentSize = originalSize;
}
public void zoomIn(int originX, int originY, int width, int height) {
// System.out.println("addTranslation: " + originX + " " + originY + " "
// + width + " " + height);
currentSize = getRectangle(originX, originY, width, height);
}
public void scale(int originX, int originY, int width, int height) {
// System.out.println("addTranslation: " + originX + " " + originY + " "
// + width + " " + height);
scaledSize = getRectangle(originX, originY, width, height);
}
public boolean isPointWithinBounds(Point point) {
return isPointWithinBounds(point.x, point.y);
}
public boolean isPointWithinBounds(int xPos, int yPos) {
boolean ret = false;
if (scaledSize != null) {
RectF sourceRec = scaledSize;
int xBounds = (int) (sourceRec.Width + sourceRec.X);
int yBounds = (int) (sourceRec.Height + sourceRec.Y);
ret = (xPos < xBounds) && (yPos < yBounds) && (xPos > sourceRec.X) && (yPos > sourceRec.Y);
}
return ret;
}
public Point transformPoint(Point point) {
return transformPoint(point.x, point.y);
}
public Point transformPoint(int xPos, int yPos) {
Point sourcePoint = new Point((int) xPos, (int) yPos);
Point retPoint = sourcePoint;
if (this.scaledSize != null) {
retPoint = transformPoint(this.scaledSize, this.currentSize, sourcePoint);
}
return retPoint;
}
/*
* Rectangle 1 has (x1, y1) origin and (w1, h1) for width and height, and
* Rectangle 2 has (x2, y2) origin and (w2, h2) for width and height, then
*
* Given point (x, y) in terms of Rectangle 1 co-ords, to convert it to
* Rectangle 2 co-ords: xNew = ((x-x1)/w1)*w2 + x2; yNew = ((y-y1)/h1)*h2 +
* y2;
*/
private Point transformPoint(RectF source, RectF destination, Point intPoint) {
PointF point = new PointF();
point.X = intPoint.x;
point.Y = intPoint.y;
return transformPoint(source, destination, point);
}
private Point transformPoint(RectF source, RectF destination, PointF point) {
return new Point((int) ((((point.X - source.X) / source.Width) * destination.Width + destination.X)),
(int) ((((point.Y - source.Y) / source.Height) * destination.Height + destination.Y)));
}
private RectF getRectangle(int x, int y, int width, int height) {
RectF rect = new RectF();
rect.X = x;
rect.Y = y;
rect.Height = height;
rect.Width = width;
return rect;
}
private PointF getPoint(int x, int y) {
PointF retPoint = new PointF();
retPoint.X = x;
retPoint.Y = y;
return retPoint;
}
public void reset() {
this.originalSize = null;
this.currentSize = null;
this.scaledSize = null;
}
}
Update:
My issue definitely seems to be with rounding. Its strange, for some test cases I need to Round Up to get the correct Point, and sometimes I need to round Up. I am missing something like a scaling factor or something. Any suggestions how to the Translation between two Rectangles correctly?
Update 2:
I tried the following method, but with still no joy:
private Point transformPoint(RectF source, RectF destination, PointF point) {
float xPercent = normalize(point.X,source.X,source.Width);
float destX = xPercent*(Math.abs(destination.Width - destination.X)) + destination.X;
float yPercent = normalize(point.Y,source.Y,source.Height);
float destY = yPercent*(Math.abs(destination.Height - destination.Y)) + destination.Y;
System.out.println("Float x,y: " + destX + ", " + destY);
System.out.println("Ceil Float x,y: " + Math.floor(destX) + ", " + Math.floor(destY) );
return new Point((int)Math.floor(destX), (int)Math.floor(destY));
}
private float normalize(float value, float min, float max) {
return Math.abs((value - min) / (max - min));
}
In running the test case and stepping through the code, my debugging shows the following substitutions...
transformPoint(RectF source, RectF destination, PointF point) {
return new Point (
(int) (((( 799 - 0 ) / 800 ) * 310 ) + 9 )),
(int) (((( 799 - 0 ) / 800 ) * 190 ) + 9 ))
);
}
The first half of the equation returns 318.6125. The second half of the equation returns 198.7625.
You need to either
modify the equation so that the int transformation truncates to the
desired value (such as + 1 at the end)
round up before conversion to int
live with the result
And as Mathew noted, multiple translations in a row distort and magnify the problem, much like averaging averages.
As stated by Reenactor, you need to round points before conversion to int:
private Point transformPoint(RectF source, RectF destination, PointF point) {
final int ptx = Math.round((((point.X - source.X) / source.Width) * destination.Width + destination.X));
final int pty = Math.round((((point.Y - source.Y) / source.Height) * destination.Height + destination.Y));
return new Point(ptx, pty);
}
Is it possible you are converting the interim results after each translation to integer points?
Remember, org.eclipse.swt.graphics.Point stores x and y as int, so any fractions in your calculations are dropped.
That is:
1) First translation:
x1 = ((799 - 0) / 800) * 301 + 9 = 309.62375
y1 = ((799 - 0) / 800) * 181 + 9 = 189.77375
If you were storing those in a Point object before going into the next translation, they would be truncated to (309, 189) and you would get
2) Second translation
x2 = ((309 - 9) / 301) * 320 + 0 = 318.93...
y2 = ((189 - 9) / 181) * 200 + 0 = 198.89...
Which would, in turn, be truncated to (318, 198).
I have a class that when clicked draws one point, when clicked again it draws another point and draws the line between them.
public class SlopeComponent extends JComponent
{
private static final long serialVersionUID = 1L;
public SlopeComponent()
{
point1 = null;
point2 = null;
class MouseSpy extends MouseAdapter
{
public void mousePressed(MouseEvent event)
{
double x1 = rxPixel(event.getX());
double y1 = ryPixel(event.getY());
point1 = new Point2D.Double(x1, y1);
double x2 = rxPixel(event.getX());
double y2 = ryPixel(event.getY());
point2 = new Point2D.Double(x2, y2);
repaint();
}
}
MouseSpy listener = new MouseSpy ();
addMouseListener(listener);
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D)g;
Axes axes = new Axes(xPixel(XMIN), xPixel(XMAX), yPixel(YMIN), yPixel(YMAX),
xPixel(0), yPixel(0), sWidth(1), sHeight(1));
axes.drawAxes(g2); //draw the axes
axes.drawTicks(g2);
if(point1 != null || point2 != null)
{
plotPoint(g2, point1);
plotPoint(g2, point2);
double x1 = point1.getX();
double y1 = point1.getY();
double x2 = point2.getX();
double y2 = point2.getY();
drawSlope(g2, x1, y1, x2, y2);
}
}
public void drawSlope(Graphics2D g2, double x1, double y1, double x2, double y2) //draw the lines
{
Point2D.Double p1 = new Point2D.Double(xPixel(x1), yPixel(y1));
Point2D.Double p2 = new Point2D.Double(xPixel(x2), yPixel(y2));
Line2D.Double line = new Line2D.Double(p1, p2);
g2.draw(line);
}
public void plotPoint(Graphics2D g2, Point2D.Double p) //plot the point
{
double x = p.getX();
double y = p.getY();
double radius = 5 * (XMAX - XMIN) / getWidth();
Ellipse2D.Double point = new Ellipse2D.Double(xPixel(x - radius), yPixel(y + radius),
sWidth(2 * radius), sHeight(2 * radius));
g2.fill(point);
double xR = Rounding.round(x, 1);
double yR = Rounding.round(y, 1);
double gap = 6 * (XMAX - XMIN) / getWidth();
g2.drawString("(" + xR + ", " + yR + ")", (float)xPixel(x + gap), (float)yPixel(y + gap));
}
public double rxPixel(double x)
{
return x * (XMAX - XMIN) / (getWidth() - 1) + XMIN;
}
public double ryPixel(double y)
{
return y * (YMIN - YMAX) / (getHeight() - 1) + YMAX;
}
public double xPixel(double xuser)
{
return (xuser - XMIN) * (getWidth() - 1) / (XMAX - XMIN);
}
public double yPixel(double yuser)
{
return (yuser - YMAX) * (getHeight() - 1) / (YMIN - YMAX);
}
public double sHeight(double yuser)
{
return yuser * (getHeight() - 1) / (YMAX - YMIN);
}
public double sWidth(double xuser)
{
return xuser * (getWidth() - 1) / (XMAX - XMIN);
}
private static final double XMIN = -10;
private static final double XMAX = 10;
private static final double YMIN = -10;
private static final double YMAX = 10;
private Point2D.Double point1;
private Point2D.Double point2;
}
However, when I try to run this, it draws both points on top of each other, then the line on top of that. I know that in my constructor I am calling getX() and getY() on the same event so that point1 and point2 have the coordinates. How do I call multiple events so that this does not happen.
You can count the clicks, you can do something like this
int count = 0;
public void mousePressed(MouseEvent event)
{
if(count == 0){
double x1 = rxPixel(event.getX());
double y1 = ryPixel(event.getY());
point1 = new Point2D.Double(x1, y1);
count++;
}
if(count == 1){
double x2 = rxPixel(event.getX());
double y2 = ryPixel(event.getY());
point2 = new Point2D.Double(x2, y2);
repaint();
}
}
I have made some progress detecting a specific kind of object. Actually a card, just like any other in your wallet.
Now I'm stuck with deskewing the photo. See:
The blue (rounded) rectangle represents the detected contour.
The purple rotate rectangle represents a RotatedRect extracted from the detected contour.
The green line is just the bounding box.
Well I need neither of those rectangles. The rectangles both have 90 degree corners. Which won't get me the perspective.
My question:
How can I get as accurate as possible all quadrangle corners from a contour?
I have created a class Quadrangle which creates the quadrangle of the 4 most largest connected polygon vertices which will intersect each other at some point. This will work in nearly any case.
If you use this code, remember to adjust the width and height in Quadrangle.warp. Note that it isn't 100% complete, the first and last polygon vertices won't be connected if they may be connect for example.
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.opencv.core.*;
import org.opencv.imgproc.Imgproc;
class Line {
public Point offset;
public double angle;
public Line(Point offset, double angle) {
this.offset = offset.clone();
this.angle = angle;
}
public Point get(int length) {
Point result = offset.clone();
result.x += Math.cos(angle) * length;
result.y += Math.sin(angle) * length;
return result;
}
public Point getStart() {
return get(-5000);
}
public Point getEnd() {
return get(5000);
}
public void scale(double factor) {
offset.x *= factor;
offset.y *= factor;
}
public static Point intersect(Line l1, Line l2) {
return getLineLineIntersection(l1.getStart().x, l1.getStart().y, l1.getEnd().x, l1.getEnd().y,
l2.getStart().x, l2.getStart().y, l2.getEnd().x, l2.getEnd().y
);
}
public static Point getLineLineIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4) {
double det1And2 = det(x1, y1, x2, y2);
double det3And4 = det(x3, y3, x4, y4);
double x1LessX2 = x1 - x2;
double y1LessY2 = y1 - y2;
double x3LessX4 = x3 - x4;
double y3LessY4 = y3 - y4;
double det1Less2And3Less4 = det(x1LessX2, y1LessY2, x3LessX4, y3LessY4);
if (det1Less2And3Less4 == 0){
// the denominator is zero so the lines are parallel and there's either no solution (or multiple solutions if the lines overlap) so return null.
return null;
}
double x = (det(det1And2, x1LessX2,
det3And4, x3LessX4) /
det1Less2And3Less4);
double y = (det(det1And2, y1LessY2,
det3And4, y3LessY4) /
det1Less2And3Less4);
return new Point(x, y);
}
protected static double det(double a, double b, double c, double d) {
return a * d - b * c;
}
}
class LineSegment extends Line implements Comparable {
public double length;
public LineSegment(Point offset, double angle, double length) {
super(offset, angle);
this.length = length;
}
public void melt(LineSegment segment) {
Point point = new Point();
point.x += Math.cos(angle) * length;
point.y += Math.sin(angle) * length;
point.x += Math.cos(segment.angle) * segment.length;
point.y += Math.sin(segment.angle) * segment.length;
angle = Math.atan2(point.y, point.x);
offset.x = (offset.x * length + segment.offset.x * segment.length) / (length + segment.length);
offset.y = (offset.y * length + segment.offset.y * segment.length) / (length + segment.length);
length += segment.length;
}
#Override
public int compareTo(Object other) throws ClassCastException {
if (!(other instanceof LineSegment)) {
throw new ClassCastException("A LineSegment object expected.");
}
return (int) (((LineSegment) other).length - this.length);
}
}
class Quadrangle {
static int
TOP = 0,
RIGHT = 1,
BOTTOM = 2,
LEFT = 3;
public Line[] lines = new Line[4];
public Quadrangle() {
}
private static double getAngle(Point p1, Point p2) {
return Math.atan2(p2.y - p1.y, p2.x - p1.x);
}
private static double getLength(Point p1, Point p2) {
return Math.sqrt(Math.pow(p2.x - p1.x, 2) + Math.pow(p2.y - p1.y, 2));
}
private static double roundAngle(double angle) {
return angle - (2*Math.PI) * Math.round(angle / (2 * Math.PI));
}
public static Quadrangle fromContour(MatOfPoint contour) {
List<Point> points = contour.toList();
List<LineSegment> segments = new ArrayList<>();
// Create line segments
for (int i = 0; i < points.size(); i++) {
double a = getAngle(points.get(i), points.get((i + 1) % points.size()));
double l = getLength(points.get(i), points.get((i + 1) % points.size()));
segments.add(new LineSegment(points.get(i), a, l));
}
// Connect line segments
double angleDiffMax = 2 * Math.PI / 100;
List<LineSegment> output = new ArrayList<>();
for (LineSegment segment : segments) {
if (output.isEmpty()) {
output.add(segment);
} else {
LineSegment top = output.get(output.size() - 1);
double d = roundAngle(segment.angle - top.angle);
if (Math.abs(d) < angleDiffMax) {
top.melt(segment);
} else {
output.add(segment);
}
}
}
Collections.sort(output);
Quadrangle quad = new Quadrangle();
for (int o = 0; o < 4; o += 1) {
for (int i = 0; i < 4; i++) {
if (Math.abs(roundAngle(output.get(i).angle - (2 * Math.PI * o / 4))) < Math.PI / 4) {
quad.lines[o] = output.get(i);
}
}
}
return quad;
}
public void scale(double factor) {
for (int i = 0; i < 4; i++) {
lines[i].scale(factor);
}
}
public Mat warp(Mat src) {
Mat result = src.clone();
Core.line(result, lines[TOP].get(-5000), lines[TOP].get(5000), new Scalar(200, 100, 100), 8);
Core.line(result, lines[RIGHT].get(-5000), lines[RIGHT].get(5000), new Scalar(0, 255, 0), 8);
Core.line(result, lines[BOTTOM].get(-5000), lines[BOTTOM].get(5000), new Scalar(255, 0, 0), 8);
Core.line(result, lines[LEFT].get(-5000), lines[LEFT].get(5000), new Scalar(0, 0, 255), 8);
Point p = Line.intersect(lines[TOP], lines[LEFT]);
System.out.println(p);
if (p != null) {
Core.circle(result, p, 30, new Scalar(0, 0, 255), 8);
}
double width = 1400;
double height = width / 2.15;
Point[] srcProjection = new Point[4], dstProjection = new Point[4];
srcProjection[0] = Line.intersect(lines[TOP], lines[LEFT]);
srcProjection[1] = Line.intersect(lines[TOP], lines[RIGHT]);
srcProjection[2] = Line.intersect(lines[BOTTOM], lines[LEFT]);
srcProjection[3] = Line.intersect(lines[BOTTOM], lines[RIGHT]);
dstProjection[0] = new Point(0, 0);
dstProjection[1] = new Point(width - 1, 0);
dstProjection[2] = new Point(0, height - 1);
dstProjection[3] = new Point(width - 1, height - 1);
Mat warp = Imgproc.getPerspectiveTransform(new MatOfPoint2f(srcProjection), new MatOfPoint2f(dstProjection));
Mat rotated = new Mat();
Size size = new Size(width, height);
Imgproc.warpPerspective(src, rotated, warp, size, Imgproc.INTER_LINEAR);
return rotated;
}
}
So I have this triangle class I need to create using an abstract class. It will also be drawn by a tester class. I am part of the way through it but I am having serious issues with the math portion. I have set the coordinates in the tester class, I have no idea of how to get the pen to turn a certain degree to draw the next side of the triangle. Attached is all the classes and I have so far. Any help will be appreciated.
Tester class
import TurtleGraphics.*;
public class TestShapes1 {
public static void main (String[] args) {
// Declare and instantiate a pen, a circle and a wheel
Pen p = new StandardPen();
//Shape s1 = new Circle1 (20, 20, 20);
//Shape s2 = new Wheel1 (-20, -20, 20, 6);
Shape1 t2 = new Triangle1 (0, 0, 50, 0, 0, 30);
// Draw the circle and wheel
//s1.draw (p);
t2.draw (p);
}
}
Shape Class
import TurtleGraphics.Pen;
public interface Shape1 {
public double area();
public void draw (Pen p);
public double getXPos();
public double getYPos();
public void move (double xLoc, double yLoc);
public void stretchBy (double factor);
public String toString();
}
Triangle Class
import TurtleGraphics.Pen;
public class Triangle1 implements Shape1 {
private double x1, y1, x2, y2, x3, y3;
private double s1, s2, s3;
private double d1, d2;
//private double height, width;
public Triangle1() {
x1 = 0;
y1 = 0;
x2 = 1;
y2 = 0;
x3 = 0;
y3 = 1;
//height = 1;
//width = 1;
}
public Triangle1 (double xLoc1, double yLoc1, double xLoc2, double yLoc2, double xLoc3, double yLoc3) {
x1 = xLoc1;
y1 = yLoc1;
x2 = xLoc2;
y2 = yLoc2;
x3 = xLoc3;
y3 = yLoc3;
//height = h;
//width = w;
}
public double area() {
return (Math.abs(x1*y2-x2*y1+x2*y3-x3*y2+x3*y1-x1*y3))/2.0;
}
public void draw (Pen p) {
s1 = Math.sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
s2 = Math.sqrt((x2-x3)*(x2-x3)+(y2-y3)*(y2-y3));
s3 = Math.sqrt((x3-x1)*(x3-x1)+(y3-y1)*(y3-y1));
p.up();
p.move (x1, y1);
p.down();
p.setDirection (0);
p.move (s1);
d1 = (Math.acos((s2*s2+s3*s3-s1*s1)/(2.0*s2*s3)))*180/Math.PI;
p.turn (180 - d1);
p.move (s2);
d2 = (Math.acos((s3*s3+s1*s1-s2*s2)/(2.0*s3*s1)))*180/Math.PI;
p.turn (180 - d2);
p.move (s3);
p.turn (-90);
//p.move ();
}
public double getXPos() {
return x1;
}
public double getYPos() {
return y1;
}
public void move (double xLoc, double yLoc) {
x1 = x1 + xLoc;
y1 = y1 + yLoc;
x2 = x2 + xLoc;
y2 = y2 + yLoc;
x3 = x3 + xLoc;
y3 = y3 + yLoc;
}
public void stretchBy (double factor) {
x1 *= factor;
y1 *= factor;
}
public String toString() {
String str = "TRIANGLE\n";
// + "Width & Height: " + width + " & " + height +"\n"
// + "(X,Y) Position: (" + xPos + "," + yPos + ")\n"
// + "Area: " + area();
return str;
}
}
You don't need any math. Just pass the degrees to p.turn(). So use
p.turn(180);
instead of
d1 = (Math.acos((s2*s2+s3*s3-s1*s1)/(2.0*s2*s3)))*180/Math.PI;
p.turn (180 - d1);
See the documentation for reference:
The degrees can be an integer or floating-point number. Example:
pen.turn(-45); Rotate the pen 45 degrees clockwise.