How to make a rectangle tangent to a circle - java

I am trying to make a rectangle object to go around a circle, with the rectangle always tangent to the circle where it is going around. I have the code that will make it go around the circle, but I don't see how to make it tangent to it. This is how it looks so far.
I am using an animation timer, since I don't know the full path that the rectangle will follow as it can change if I it finds something blocking it.
I can make the rectangle go around the circle in a smooth way, but I don't know how to make the rectangle tangent to it.
public void moveInCircle(double radius)
{
double newX = getX() + (radius * Math.cos(Math.toDegrees(angle)));
double newY = getY() + (radius * Math.sin(Math.toDegrees(angle)));
vehicle.setTranslateX(newX);
vehicle.setTranslateY(newY);
}
I know that the tangent will be the adjacent side(x) divided by the opposite side (y), but I don't understand how to incorporate it.

I recommend using a Rotate transform. This way you only need to set the initial position and the pivot point and can restrict the updates to the Rotate.angle property.
The following example uses a Timeline to animate the property, but this could easily be done from the moveCircle method by using rotate.setAngle(angleDegrees);:
#Override
public void start(Stage primaryStage) {
Pane root = new Pane();
root.setMinSize(500, 500);
final double radius = 150;
final double centerX = 250;
final double centerY = 250;
final double height = 40;
Circle circle = new Circle(centerX, centerY, radius, null);
circle.setStroke(Color.BLACK);
// rect starts at the rightmost point of the circle touching it with the left midpoint
Rectangle rect = new Rectangle(centerX + radius, centerY - height / 2, 10, height);
rect.setFill(Color.RED);
Rotate rotate = new Rotate(0, centerX, centerY); // pivot point matches center of circle
rect.getTransforms().add(rotate);
// animate one rotation per 5 sec
Timeline animation = new Timeline(
new KeyFrame(Duration.ZERO, new KeyValue(rotate.angleProperty(), 0d)),
new KeyFrame(Duration.seconds(5), new KeyValue(rotate.angleProperty(), 360d)));
animation.setCycleCount(Animation.INDEFINITE);
animation.play();
root.getChildren().addAll(circle, rect);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
Btw: the following part of your code seems odd
double newX = getX() + (radius * Math.cos(Math.toDegrees(angle)));
double newY = getY() + (radius * Math.sin(Math.toDegrees(angle)));
Math.sin and Math.cos expect radians, not degree. You either need to use toRadians or don't require a conversion...

Related

draw images with random rotation java + processing

I'm drawing arrows using Java and I can draw them straight but now I need to have the arrows pointing in different directions.
In my current code, I draw a triangle and then a square.
Is there a way to group the two after they've been drawn and then rotate them at a random angle?
Right now I'm only able to rotate the triangle and square separately, causing some messy thing.
void setup() {
size(400, 400);
}
void draw() {
float r = random(24, 64);
background(255);
drawArrow(r);
//drawPlus(r);
saveFrame("dataArrow/plus####.png");
if (frameCount == 100) {
exit();
}
}
void drawArrow(float r){
float base = r * 2;
float xStart = random(1, width-base - 1);
float xEnd = xStart + base;
float k = 0.5 * base;
float y = random(k, width-k);
float middleBase = base/2 + xStart;
float rectSide = 0.5 * base;
float rectX1 = middleBase - rectSide/2;
float rectX2 = middleBase + rectSide/2;
fill(0);
triangle(xStart, y, xEnd, y, middleBase, y - k);
rect(rectX1, y, rectSide, rectSide);
}
not sure if this exactly what you mean but here is how to move things around
push and pop matrix allows you to organize things that should have the same translations
https://processing.org/reference/pushMatrix_.html
https://processing.org/reference/rotate_.html
https://processing.org/reference/translate_.html
basic example
pushMatrix();//start of new translation and rotation things
translate(xAmount,yAmount);//this moves the origin
rotate(angle);//this rotates around origin
//drawing around the point of rotation 0,0 here
//drawing...
popMatrix();//reset all translations and rotations to before

Rotate Rectangle 2D For Hit Detection

I was looking to rotate a rectangle by a specific angle, as I have a game using java fx which has comets move at an angle. If the rocket intersects with that comet, the game is over. However, a diagonal comet possesses a rectangle at 0 degrees, which covers unnecessary space. I tried using following code, but the rectangles are still 0 degrees:
public void isRocketHit(){
Rectangle2D rocketrec = new Rectangle2D(rocket.getX(), rocket.getY(), rocket.getImage().getWidth(), rocket.getImage().getHeight());
for(Streak i : rstreaks){
double width = i.getImage().getWidth();
double height = i.getImage().getHeight();
Rectangle2D cometrec = new Rectangle2D(i.gmarkX(), i.gmarkY(), width, height);
double rotationCenterX = (i.gmarkX() + width)/2;
double rotationCenterY = (i.gmarkY() + height)/2;
gc.save();
gc.translate(rotationCenterX, rotationCenterY);
gc.rotate(i.getAngle());
gc.translate(-rotationCenterX, -rotationCenterY);
gc.fillRect(i.gmarkX(), i.gmarkY(), width, height);
gc.setFill(Color.AZURE);
if(rocketrec.intersects(cometrec)){
play = false;
System.out.println("HIT");
}
gc.restore();
}
}

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.

Translate Java 3D coordinates to 2D screen coordinates

I'm working with a Java 3D application called "Walrus" that is used to display directed graphs. The code already has a feature to highlight a node and draw label adjacent in graph given its screen coordinates.
Upon rotating the screen, the node is no more highlighted.
What I have is the node coordinates in 3D. I need to draw label to it.
Code for highlight using 3D coordinates
Point3d p = new Point3d();
m_graph.getNodeCoordinates(node, p);
PointArray array = new PointArray(1, PointArray.COORDINATES);
array.setCoordinate(0, p);
m_parameters.putModelTransform(gc);
gc.setAppearance(m_parameters.getPickAppearance());
How can I draw Label with 3D coordinates( Raster graphics throws error Renderer: Error creating immediate mode Canvas3D graphics context )
How can I convert 3D coordinates to 2D screen and use existing code to draw label at 2D screen point
Thanks,
Dakshina
I have an algorithm/method for converting [x,y,z] into [x,y] with the depth parameter:
The x value is : (int) (x - (z / depth * x))
The y value is : (int) (y - (z / depth * y))
Essentially, the depth is the focal point. The vanishing point will be at [0,0,depth].
Here's what i used to convert my 3D coordinates into perspective 2D, x2 and y2 being the 2dimensional coordinates, xyz being the 3D coordinates.
use these formulas:
x2 = cos(30)*x - cos(30)*y
y2 = sin(30)*x + sin(30)*y + z
I picked the angle 30 as it is easy for perspective purposes, also used in Isometric grids for drawing 3D on 2D papers. As the z axe will be the vertical one, x and y are the ones at 60 degrees from it right and left. Isometric Grid Picture.
I'm still working on rotation, but without altering the axes, just coordinate rotation in 3D.
Enjoy.
I found the solution.
This is the function to display Text3D at image 2D coordinates
public void drawLabel(GraphicsContext3D gc, double x, double y, int zOffset, String s) {
boolean frontBufferRenderingState = gc.getFrontBufferRendering();
gc.setBufferOverride(true);
gc.setFrontBufferRendering(true);
Point3d eye = getEye();
double labelZ = zOffset * LABEL_Z_OFFSET_SCALE
+ LABEL_Z_SCALE * eye.z + LABEL_Z_OFFSET;
double xOffset = LABEL_X_OFFSET * m_pixelToMeterScale;
double yOffset = LABEL_Y_OFFSET * m_pixelToMeterScale;
Point3d p = new Point3d(x + xOffset, y + yOffset, 0.0);
{
// Project given (x, y) coordinates to the plane z=labelZ.
// Convert from image-plate to eye coordinates.
p.x -= eye.x;
p.y -= eye.y;
double inversePerspectiveScale = 1.0 - labelZ / eye.z;
p.x *= inversePerspectiveScale;
p.y *= inversePerspectiveScale;
// Convert from eye to image-plate coordinates.
p.x += eye.x;
p.y += eye.y;
}
Transform3D scale = new Transform3D();
scale.set(LABEL_SCALE);
Vector3d t = new Vector3d(p.x, p.y, labelZ);
Transform3D translation = new Transform3D();
translation.set(t);
translation.mul(scale);
Transform3D transform = new Transform3D(m_imageToVworld);
transform.mul(translation);
gc.setModelTransform(transform);
//-----------------
int fontSize=(int)(10*m_magnification);
if(fontSize>20)
fontSize=20;
//---------------
// XXX: Courier may not be available on all systems.
Text2D text = new Text2D(s, new Color3f(1.0f, 1.0f, 1.0f),
"Courier", fontSize, Font.BOLD);
gc.draw(text);
gc.flush(true);
// NOTE: Resetting the model transform here is very important.
// For some reason, not doing this causes the immediate
// following frame to render incorrectly (but subsequent
// frames will render correctly). In some ways, this
// makes sense, because most rendering code assumes that
// GraphicsContext3D has been set to some reasonable
// transform.
gc.setModelTransform(m_objectTransform);
gc.setFrontBufferRendering(frontBufferRenderingState);
}
This is the function to take 3D coordinates and convert them to image 2D coordinates and render using above function
private boolean displayOnScreenLabel(int node, String label) {
boolean success = false;
try {
Transform3D transform = m_parameters.getObjectToEyeTransform();
Point3d nodeC = new Point3d();
m_graph.getNodeCoordinates(node, nodeC);
transform.transform(nodeC);
Point3d eye = m_parameters.getEye();
double perspectiveScale = 1.0 / (1.0 - nodeC.z / eye.z);
double centerX = eye.x + nodeC.x * perspectiveScale;
double centerY = eye.y + nodeC.y * perspectiveScale;
GraphicsContext3D gc = m_canvas.getGraphicsContext3D();
m_parameters.drawLabel(gc, centerX, centerY, m_labelZOffsetCounter++, label);
success = true;
} catch (final java.lang.OutOfMemoryError error) {
JOptionPane.showMessageDialog(m_frame, "The 3D Graphics is unable to find enough memory on your system. Kill the application!", "Out Of Memory!", JOptionPane.ERROR_MESSAGE);
} catch (Exception e) {
success = false;
}
return success;
}

Rotate Rectangle in Java

I need to create rectangles that are rotated around their center (so they don't need to be parallel to the axes of the coordinate system). So basicelly each rectangle can be defined by center-X, center-Y, width, height and angle. What I want to do then is to perform calculations on whether certain points are contained in these rectangles or not (so no drawing will be involved). I guess I cant use the Rectangle2D class because these rectangles will always be parallel to the x and y-axis of the coordinate system. Is the only way to get this functionality by writing my own rectangle class or is there anything existing (similar to Rectangle2D) I can use?
Rotate all the points you want to test and use contains(Point) method of the Rectangle2D as Mihai did.
But if you really want to rotate the rectangles you can do it like this (this is the integer version but probably you can do it with Rectangle2D aswell :)).
public class TestRotate {
public static void main(String... args) {
Rectangle r = new Rectangle(50, 50, 100, 100);
Point check = new Point(100, 151); // clearly outside
System.out.println("first: " + r.contains(check));
AffineTransform at = AffineTransform.getRotateInstance(
Math.PI/4, r.getCenterX(), r.getCenterY());
Polygon p = new Polygon();
PathIterator i = r.getPathIterator(at);
while (!i.isDone()) {
double[] xy = new double[2];
i.currentSegment(xy);
p.addPoint((int) xy[0], (int) xy[1]);
System.out.println(Arrays.toString(xy));
i.next();
}
// should now be inside :)
System.out.println("second: " + p.contains(check));
}
}
You can use Rectangle2D to check for containment, if instead of rotating your rectangle by an angle, say, counterclockwise, you rotate each of the points you need to check by the same angle clockwise, relative to the center of the rectangle. Something like
double dx = point.x - rectangleCenter.x;
double dy = point.y - rectangleCenter.y;
double newX = rectangleCenter.x - dx*Math.cos(angle) + dy*Math.sin(angle);
double newY = rectangleCenter.x - dx*Math.sin(angle) - dy*Math.cos(angle);

Categories