Polygon shape shrinks when it rotates - java

I am struggeling with the rotation of 6 points. These points rotate around a center point in the middle. But what happens is that the shapes area shrinks, and gets smaller and smaller.
The Drawing of the shape takes place on i JPanel with PaintComponent. This means that the canvas only supports integers positioning altough I can store positions in Doubles.
I use Point2D.Double for storing the points position
I Rotate all the points by 1 deegre at each function call
I think my understanding of the rotation is lacking, I can rotate 360 deegre in one call, or 180, this works fine. But 45 deegres or 90 will completely turn my points into a line(picture below).
This problem has been bothering me for a while now, but as always, I am sure there is a simple solution.
Here is the rotation Function
#Override
public synchronized void rotatePoints(int move_x, int move_y) {
// TODO Auto-generated method stub
super.rotatePoints(move_x, move_y);
BottomPanel.appendText("Area of Polygon is: " + UtilClass.calculateAreaOfPolygon(points)+ "\n");
double degrees=1.0;
double radians = degrees * (double)(Math.PI / 180.0);
//GET THE CENTER POINT C
Point2D.Double center = UtilClass.getCenterOfPolygon(points);
//ITERATE THROUGH THE POINTS
Iterator<PointClass> itr = points.iterator();
while(itr.hasNext()) {
//GET THE POINT
PointClass point_class = itr.next();
//point_class = points.get(3);
//FIRST TRANSLATE THE DIFFERENCE
double x1 = point_class.point.x - center.x;
double y1 = point_class.point.y - center.y;
//APPLY ROTATION MATRIX
x1 = (x1 * Math.cos(radians)) - (y1 * Math.sin(radians));
y1 = (x1 * Math.sin(radians)) + (y1 * Math.cos(radians));
//TRANSLATE BACK
point_class.point.setLocation(x1 + center.x, y1 + center.y);
//ADD THE DEEGRES TO POINT CLASS
point_class.angle += Math.toDegrees(radians);
}
}
Here is the code for retriving a center location of a given polygon
public synchronized static Point2D.Double getCenterOfPolygon(List<PointClass> points) {
//GETTING THE CENTER OF A COMPLEX POLYGON
double combined_x = 0;
double combined_y = 0;
Iterator<PointClass> itr = points.iterator();
while(itr.hasNext()) {
PointClass point_class = itr.next();
//ADD TO THE
combined_x += point_class.point.x;
combined_y += point_class.point.y;
}
double center_x = combined_x / (double)points.size();
double center_y = combined_y / (double)points.size();
return new Point2D.Double(center_x, center_y);
}
Here is a picture of the shape rotating all its points by 1 deegre clockwise
After each rotation I output the area of the polygon
here is the result
Area of Polygon is: 6290
Area of Polygon is: 6288
Area of Polygon is: 6286
Area of Polygon is: 6284
Area of Polygon is: 6283
Area of Polygon is: 6281
Here is a picture of the shape rotating all its points by 90 deegre clockwise after one call.
It clearely does not want to do that.
I would be glad for any suggestions or tips.

The error lies here:
//APPLY ROTATION MATRIX
x1 = (x1 * Math.cos(radians)) - (y1 * Math.sin(radians));
y1 = (x1 * Math.sin(radians)) + (y1 * Math.cos(radians));
x1 is being updated too early, such that y1 is calculated based on the new value of x1 instead of the old value.
You could change it to something like this:
//APPLY ROTATION MATRIX
double temp;
temp = (x1 * Math.cos(radians)) - (y1 * Math.sin(radians));
y1 = (x1 * Math.sin(radians)) + (y1 * Math.cos(radians));
x1 = temp;

Related

Draw Fibonacci Arcs

I am attempting to create an application that draws Fibonacci Arcs similar to these.
However, I'd like full circles instead of arcs, and I'd like to draw more than the three Fibonacci lines shown in the picture. I've created an application using JFreeChart to attempt to accomplish this. However, here is the result when trying to draw the same arcs (but as circles) shown in the previous picture.
Initially, it just looks wrong, but when I zoom out, it is indeed a circle, but it's way too big.
To calculate the arcs, you draw a line, then take a Fibonacci ratio - let's use .381 for example - the percentage of that line. If you look at the first picture, you'll see the innermost arc intersects the line at .381% the distance of the line from the centre of the circle. First I calculate this point. Then I construct a line from the .381% point to the centre. Then I take the distance of this line, which should be the radius. Then I use this radius to draw the circle.
Here's the code to calculate the radius. Where stop and start are the stop and start points of the line drawn.
multiplier = ratio38Value + i;
diffx = (stop.getX() - start.getX()) * multiplier;
diffy = (stop.getY() - start.getY()) * multiplier;
xValue = start.getX() + diffx;
yValue = start.getY() + diffy;
point = new Point(xValue, yValue);
lineSegment = new Line(point, stop);
radius = lineSegment.getDistance();
circle = new Circle(stop.getX(), stop.getY(), radius);
circles.add(circle);
Here is the code to calculate the distance of a line
public double getDistance(){
double x = Math.pow(endPoint.getX() - startPoint.getX(), 2);
double y = Math.pow(endPoint.getY() - startPoint.getY(), 2);
return Math.sqrt(x + y);
}
I get back a list of circle objects (this is an object I created that holds the radius and centre point) one for each circle that needs to be drawn and then draw them.
List<Circle> circles = fibonacciCalculations.getFibonacciArcs(startPoint, endPoint);
if(circles != null)
{
for (Circle circle : circles){
double xCenter = circle.getX();
double yCenter = circle.getY();
double radius = circle.getRadius();
plot.addAnnotation(new XYShapeAnnotation(new Ellipse2D.Double(xCenter - radius, yCenter - radius, radius + radius, radius + radius)));
}
}
I think the issue has something to do with how the x-axis of time and the y axis of price doesn't exactly correlate. What I mean is, if the radius is 20, you'll be going 20 units away from the centre at each point. So say you're stock price is only 5 dollars, at your lowest point you will then be at -15. If that is the case, I have no idea how to fix it. But it also could be some error in my logic. Any ideas would be appreciated.
EDIT: While the bars look like they may be weekly bars in the first picture, they are indeed daily bars. Also, I have already converted the coordinates from data space to x y coordinates. I use this code below to do that.
#Override
public void chartMouseMoved(ChartMouseEvent event) {
Rectangle2D dataArea = cp.getScreenDataArea();
JFreeChart chart = event.getChart();
XYPlot plot = (XYPlot) chart.getPlot();
ValueAxis xAxis = plot.getDomainAxis();
ValueAxis yAxis = plot.getRangeAxis();
double x = xAxis.java2DToValue(event.getTrigger().getX(), dataArea,
RectangleEdge.BOTTOM);
double y = yAxis.java2DToValue(event.getTrigger().getY(), dataArea,
RectangleEdge.LEFT);
I'm not sure of the proper terminology, so lets call the actual (x,y) coordinates that represent where you are on your monitor "screen space" and let's call the (x,y) coordinates of the chart "chart space".
My issue was I was converting the points from screen space to chart space and then calculating my points. Instead, I should have calculated all my points in screen space, and then converted each calculated point to chart space.
Where i is the amount of groups of arcs I want to draw. (i = 0, then I am drawing circles for the 38, 50, 62 ratios, i = 1 then I'm drawing circles for the -1.68, -1.50...1.50, 1.68 ratios) I use this code to get my points that are a given ratio between the center and the starting point.
multiplier = ratio62Value + i;
diffx = (stop.getX() - start.getX()) * multiplier;
diffy = (stop.getY() - start.getY()) * multiplier;
xValue = start.getX() + diffx;
yValue = start.getY() + diffy;
point = new Point(xValue, yValue);
line = new Line(point, stop);
line.calculateCirclePoints();
Here is the method to calculate the points on the circle. Where, endPoint is the center point, and the radius is the distance from the start point to the end point.
public void calculateCirclePoints(){
double radius = getDistance();
double radians;
double x;
double y;
Point currentPoint;
for (int degrees = 0; degrees <= 360; degrees += 1){
radians = Math.toRadians(degrees);
x = endPoint.getX() + (radius * Math.cos(radians));
y = endPoint.getY() + (radius * Math.sin(radians));
currentPoint = new Point(x, y);
points.add(currentPoint);
}
}
Lastly, I convert all of these points to chart space, and draw them on the chart.
public static Point converPointTo2D(Point point, Rectangle2D dataArea, XYPlot plot){
double x;
double y;
CustomNumberAxis xAxis = (CustomNumberAxis) plot.getDomainAxis();
CustomNumberAxis yAxis = (CustomNumberAxis) plot.getRangeAxis();
x = xAxis.java2DToValue(point.getX(), dataArea,
RectangleEdge.BOTTOM);
y = yAxis.java2DToValue(point.getY(), dataArea,
RectangleEdge.RIGHT);
return new Point(x, y);
}
One point to note, the radius of the circles is dependent on how much of a specific chart you're showing. A circle drawn on a 1 year chart from point a to point b will be smaller than a circle drawn on a 5 year chart from those same points.

Calculate a point which is perpendicular to a line

I have two points store in two variable, which forms a line. I want to find a point which is perpendicular to that line from one end point in that line.
Suppose I have two points P1(x1,y1) and P2(x2,y2) then i want to find a third point P3 such that line(P1-P2) is perpendicular to line(P2,P3) and intersect at P2.
First, the angle:
public static double angle (double x1, double y1, double x2, double y2) {
double xdiff = x1 - x2;
double ydiff = y1 - y2;
//double tan = xdiff / ydiff;
double atan = Math.atan2(ydiff, xdiff);
return atan;
}
To get the perpendicular, you must add PI/2 to the angle of the line defined by your two points.
Once you have that angle, the formula is:
x = interceptPt.x + sin(perp_angle) * distance;
y = interceptPt.y + cos(perp_angle) * distance;
If you want to use Java I can recommend to use JTS. Create a LineSegment and use the pointAlongOffset method. Given Points p1 and p2 the code would look like that:
// create LineSegment
LineSegment ls = new LineSegment(p1.getX(), p1.getY(), p2.getX(), p2.getY());
// perpendicular distance to line
double offsetDistance = 10;
// calculate Point right to start point
Coordinate startRight = ls.pointAlongOffset(0, offsetDistance);
// calculate Point left to start point
Coordinate startLeft = ls.pointAlongOffset(0, -offsetDistance);
// calculate Point right to end point
Coordinate endRight = ls.pointAlongOffset(1, offsetDistance);
// calculate Point left to end point
Coordinate endLeft = ls.pointAlongOffset(1, -offsetDistance);
ControlAltDel is already answered but he did a mistake, replaced cos to sin
x = interceptPt.x + cos(angle + 90) * distance;
y = interceptPt.y + sin(angle + 90) * distance;
x,y is point away from (interceptPt.x,interceptPt.y) at (distance) .
(interceptPt.x,interceptPt.y) is point in your line where perpendicular start to drawn.
angle = your line angle with horizontal axis
I got the answer at http://jsfiddle.net/eLxcB/2/
// Start and end point
var startX = 120
var startY = 150
var endX = 180
var endY = 130
R.circle(startX,startY,2);
// Calculate how far above or below the control point should be
var centrePointX = startX
var centrePointY = startY;
// Calculate slopes and Y intersects
var lineSlope = (endY - startY) / (endX - startX);
var perpendicularSlope = -1 / lineSlope;
var yIntersect = centrePointY - (centrePointX * perpendicularSlope);
// Draw a line between the two original points
R.path('M '+startX+' '+startY+', L '+endX+' '+endY);
// Plot some test points to show the perpendicular line has been found
R.circle(100, (perpendicularSlope * 100) + yIntersect, 2);
You can store your points in vec2d, then use some mathematical equations to get the perpendicular point.
vec2d getPerpendicularPoint(vec2d A, vec2d B, float distance)
{
vec2d M = (A + B) / 2;
vec2d p = A - B;
vec2d n = (-p.y, p.x);
int norm_length = sqrt((n.x * n.x) + (n.y * n.y));
n.x /= norm_length;
n.y /= norm_length;
return (M + (distance * n));
}

Why isn't my method to rotate a point around another point working?

I have a method in my android app that looks like this:
//get point after rotation
public static PointF getRotatedPoint(PointF pt,PointF center, float degrees)
{
double angleInRadians = degrees * (Math.PI / 180);
pt.x = (float) (Math.cos(angleInRadians) * (pt.x-center.x) - Math.sin(angleInRadians) * (pt.y-center.y) + center.x);
pt.y = (float) (Math.sin(angleInRadians) * (pt.x-center.x) + Math.cos(angleInRadians) * (pt.y-center.y) + center.y);
return pt;
}
I have a rectangle that I rotate by 45 degrees. I can touch any point on the rotated rectangle and it gives me the touched point I want to get the coordinates of the point if the rectangle wasn't rotated. So I pass in -45 in the degrees argument. Here is how I call it:
getRotatedPoint(touchedPoint, centerOfRectangle,-45);
When I draw the point on the rectangle before it gets rotated, it gives me a result close to the position I touched on the rotated rectangle but off by a pretty big difference.
Here is a picture to explain my problem:
I think this might be a problem with my math so any answers are greatly appreciated.
You are mixing initial and final values in the calculations. You re-assign pt.x:
pt.x = (float) (Math.cos(angleInRadians) * (pt.x-center.x) - Math.sin(angleInRadians) * (pt.y-center.y) + center.x);
which doesn't immediately pose any problems. But the calculation for pt.y relies on the original value of pt.x, not the rotated value:
pt.y = (float) (Math.sin(angleInRadians) * (pt.x-center.x) + Math.cos(angleInRadians) * (pt.y-center.y) + center.y);
Thus just use some temporary variables to hold the initial values.
public static PointF getRotatedPoint(PointF pt,PointF center, float degrees)
{
double x0 = pt.x;
double y0 = pt.y;
double angleInRadians = degrees * (Math.PI / 180);
pt.x = (float) (Math.cos(angleInRadians) * (x0-center.x) - Math.sin(angleInRadians) * (y0-center.y) + center.x);
pt.y = (float) (Math.sin(angleInRadians) * (x0-center.x) + Math.cos(angleInRadians) * (y0-center.y) + center.y);
return pt;
}

Transform + scale a set of points

I wrote a gui where a user draws something in a (640x480) window. It makes that drawing into a set of points stored in a Vector array. Now, how do I translate those set of points to the origin (0,0 top left corner of the window) or put it at a specified pos? The width and height of the window I want it in is also 640x480.
After that is solved, how do you scale that new set of points to a size I want?
UPDATE 1
I solved the scale issue, but not the positioning issue. The drawing is not going where I tell it to be. Code below of what I have so far.
float scaleX = (float)width/boundingPoints.width;
float scaleY = (float)height/boundingPoints.height;
for(int i = 0; i < cg_points.size()-1; i++){
Point p1 = cg_points.get(i);
Point p2 = cg_points.get(i+1);
g.drawLine((int)(p1.x*scaleX) + pos.x, (int)(p1.y*scaleY) + pos.y, (int)(p2.x*scaleX) + pos.x, (int)(p2.y*scaleY) + pos.y);
}
I want the drawing to start at where pos [x, y] is. What is currently the problem is this. It does follow what pos.x and pos.y does, but it is way off and not starting at pos[x,y].
Here is a screen shot of the issue
As you can see from the picture, the box is where the star is supposed to be. The scaling is right as you can see, just not the pos. That is because the points in the drawing may NOT start at (0,0).
Any suggestions?
Thanks!
To translate a drawing, simply
foreach point in array
point.x += translate.x
point.y += translate.y
If you're going to center a drawing, pick a center (such as averaging all your points), negate that value, then translate all your points by that value.
To scale a drawing:
foreach point in array
point.x *= scale
point.y *= scale
So I solved it...YAY!!! Here is the code below in case you run into the same issue as I had.
float scaleX = (float)width/boundingPoints.width;
float scaleY = (float)height/boundingPoints.height;
int bx = boundingPoints.x;
int by = boundingPoints.y;
for(int i = 0; i < cg_points.size()-1; i++){
Point p1 = cg_points.get(i);
Point p2 = cg_points.get(i+1);
int x1 = (int) ((p1.x-bx)*scaleX);
x1 += pos.x;
int y1 = (int) ((p1.y-by)*scaleY);
y1 += pos.y;
int x2 = (int) ((p2.x-bx)*scaleX);
x2 += pos.x;
int y2 = (int) ((p2.y-by)*scaleY);
y2 += pos.y;
g.drawLine(x1, y1, x2, y2);
}

Java OpenGL: Mouse picking in 3D Space

I am trying to make some sort of 3D Editor with Java and OpenGL. And now I'm implementing the basic functions of an 3D Editor like rotating the camera around a specific Position and zooming. Next I want to do a 3D Picking to select Objects,Lines and Vertices in 3D-Space with the Mouse. I thought this is gonna to be easy because I can already select Objects when the Camera is focusing them.
Here is the example of the Selection of Objects with the Camera focus:
In the Class Camera there is this Method:
public boolean isVecInFocus(Vec3 vec) {
//returns the distance between camera and target
float c = new Vec3(posX,posY,posZ).getDistanceTo(vec);
// returns a Vector by drawing an imiginary line with the length of c and the position and rotation of the camera
Vec3 target = getFocusedPoint(c);
//checks if the calculated Vector is near to the target
if(target.x > vec.x - 0.05f && target.x < vec.x + 0.05f && target.y > vec.y - 0.05f && target.y < vec.y + 0.05f && target.z > vec.z - 0.05f && target.z < vec.z + 0.05f) {
return true;
} else {
return false;
}
}
Now, I want to do the same with the Mouse input:
//Mouse positions
float mX = Mouse.getX();
float mY = Mouse.getY();
//My test Vector
Vec3 vec = new Vec3(-5,5,-8);
//Camera Position
Vec3 camV = new Vec3(cam.getPosX(),cam.getPosY(),cam.getPosZ());
//Distance from Test Vector to Camera
float c = camV.getDistanceTo(vec);
//Calculating of the aspect between width and height (Because fov_x and fov_y are different because of the Screen Resolution, I think)
float aspect = (float) sb.getDisplayWidth() / (float) sb.getDisplayHeight();
//Normal fov refers to fov_y, so here is the fov_x
float fovx = cam.fov * aspect;
//Changing the Rotations to calculate the target Vector with the values of the Mouse position and rotations , not the Camera
float rotY = cam.getRotationY() + (fovx / (float) sb.getDisplayWidth()) * (mX) - (fovx / 2F);
float rotX = cam.getRotationX() + (cam.fov / (float) sb.getDisplayHeight()) * ((float) sb.getDisplayHeight() - mY) - (cam.fov / 2F);
//Calculating the target Vector with simple Math ...
double xDis = c * Math.sin(Math.toRadians(rotY)) * Math.cos(Math.toRadians(rotX));
double yDis = c * Math.sin(Math.toRadians(rotX));
double zDis = c * Math.cos(Math.toRadians(rotY)) * Math.cos(Math.toRadians(rotX));
float posX = (float) (camV.x + xDis);
float posY = (float) (camV.y - yDis);
float posZ = (float) (camV.z - zDis);
Vec3 target = new Vec3(posX,posY,posZ);
//Check if the target Vector and the Test Vector are the same.
If I use this Code, and point with my Mouse at the Test-Vector, the result is not right. The accuracy of the Point gets lower, the bigger the difference between Screen-middle and Mouse position is.
I think it has something to do with the OpenGL Perspective, but I'm not sure ...

Categories