I have an image with a softcrop.
i.e
The image bounds are width 3 and height 5.
In the image I have a soft crop at (x,y) 1,4 and bounds width 1 and height 1.
How can I get the new position (x,y) for the crop after I rotate the image 90 degrees?
AffineTransform perhaps?
Yes you can use AffineTransform.
You can use AffineTransform.getRotateInstance and AffineTransform#transform(Point2D, Point2D).
Use it like so:
AffineTransform transform = AffineTransform.getRotateInstance(Math.PI / 2.0, width / 2.0, height / 2.0);
Point2D.Double point = new Point2D.Double(1, 4);
Point2D.Double result = new Point2D.Double();
transform.transform(point, result);
Please note that the top left point of the soft crop area will no longer be the top left point after rotation but the bottom left.
Related
What I'm trying to do:
Create a compass when given a direction in degrees (0 - 360). Like so:
What I have done:
I have managed to get the SVG image to point in the right direction but I can't seem to get it to rotate around the circle. To attempt a solution around the circle, I have decided to try get the positioning using the ellipse tool and this formula. This is what it looks like at the moment:
(notice how the arrow faces a different direction to the ellipse, in the circle, on the axis - given the center point is the middle of the green circle)
void setDirection(float value, int radius) {
fill(secondaryColour);
float origin_x = (1280 - (width-400)/2);
float origin_y = height/2;
float x = origin_x + radius * cos(radians(value));
float y = origin_y +radius * sin(radians(value));
//grey circle
ellipse(x, y, 20, 20);
//arrow SVG
pushMatrix();
translate(200, 300);
rotate(radians(value));
scale(0.5);
shape(arrow);
popMatrix();
}
Please note: value is in degrees and radius is the radius I want the arrow to sit on. What am I doing wrong with the ellipse? and how can I bring them both together?
I found that the starting angle started on the white line, but I was assuming it would start on the red (similar to the angle of the arrow). To resolve the issue I needed to subtract 90 degrees from the variable value before converting it into radians.
I draw a rectangle with coordinates (x = 100, y = 100, width = 200, height = 100). Then I turn the shape of this rectangle around the center.
this.rotation.addListener((obs, old, fresh) -> {
Rotate rotate = new Rotate();
rotate.setAngle((double) fresh - (double) old);
rotate.setPivotX(x.getValue().doubleValue() + (width.getValue().doubleValue() / 2));
rotate.setPivotY(y.getValue().doubleValue() + (height.getValue().doubleValue() / 2));
shape.getTransforms().addAll(rotate);
});
How now to find out the coordinates of shape?
You can use the localToParent method to transform a point from the coordinate system of the Rectangle to the coordinate system of the parent.
Point2D topLeftInParent = shape.localToParent(shape.getX(), shape.getY());
If you simply need the x/y range in the parent where the Rectangle is displayed, you could also use getBoundsInParent:
Bounds parentBounds = shape.getBoundsInParent();
BTW: I do not recommend adding a new transform on every change. Instead I recommend adjusting the existing rotation:
Rotate rotate = new Rotate(0, shape.getX() + shape.getWidth()/2, shape.getX() + shape.getHeight()/2);
shape.getTransforms().add(rotate);
rotate.angleProperty().bind(this.rotation);
I'm working with PDFBox and trying to rotate an image and have it position correctly on the screen. The design editor I'm using outputs the following information about images that may be useful.
Image bounding box top-left coords (I'm using the bottom left coords to better suit PDFBox coord space.)
Image rotation in degrees
Image width & height
The translation appears to be off.
// Rotation
AffineTransform rotation = new AffineTransform();
rotation.rotate(Math.toRadians(360 - element.getAngle()),
element.getLeft() + scaledWidth/2,
adjustedYPos + scaledHeight/2);
stream.transform(new Matrix(rotation));
// Position & scale
AffineTransform mat = new AffineTransform(scaledWidth,
0,
0,
scaledHeight,
element.getLeft(),
adjustedYPos);
// Draw the final image
stream.drawImage(pdfImage, new Matrix(mat));
Rotations are based on the center of the image as an anchor point.
You can correctly position images using code like this:
void placeImage(PDDocument document, PDPage page, PDImageXObject image, float bbLowerLeftX, float bbLowerLeftY, float width, float height, float angle) throws IOException {
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page, AppendMode.APPEND, true, true) ) {
float bbWidth = (float)(Math.abs(Math.sin(angle))*height + Math.abs(Math.cos(angle))*width);
float bbHeight = (float)(Math.abs(Math.sin(angle))*width + Math.abs(Math.cos(angle))*height);
contentStream.transform(Matrix.getTranslateInstance((bbLowerLeftX + .5f*bbWidth), (bbLowerLeftY + .5f*bbHeight)));
contentStream.transform(Matrix.getRotateInstance(angle, 0, 0));
contentStream.drawImage(image, -.5f*width, -.5f*height, width, height);
}
}
(PlaceRotatedImage utility method)
This method accepts coordinates as they are meaningful in the context of PDF, i.e. coordinate values and dimensions according to the default user space coordinate system of the given page (y values increasing upwards, the origin arbitrary but fairly fairly often in the lower left), (bounding) box given by lower left corner, angles as in math in counterclockwise radians...
If you need the parameters differently, you can fairly easily adapt the method, though. If you e.g. get the upper left corner of the bounding box instead of the lower left, you can simply subtract the bounding box height determined in the method as bbHeight to calculate the lower left y coordinate used here.
You can use this method like this:
PDPage page = ...;
PDRectangle mediaBox = page.getMediaBox();
float bbLowerLeftX = 50;
float bbLowerLeftY = 100;
try ( PDPageContentStream contentStream = new PDPageContentStream(document, page) ) {
contentStream.moveTo(bbLowerLeftX, mediaBox.getLowerLeftY());
contentStream.lineTo(bbLowerLeftX, mediaBox.getUpperRightY());
contentStream.moveTo(mediaBox.getLowerLeftX(), bbLowerLeftY);
contentStream.lineTo(mediaBox.getUpperRightX(), bbLowerLeftY);
contentStream.stroke();
}
PDImageXObject image = PDImageXObject.createFromByteArray(document, IOUtils.toByteArray(resource), "Image");
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, image.getWidth(), image.getHeight(), (float)(Math.PI/4));
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .5f*image.getWidth(), .5f*image.getHeight(), 0);
placeImage(document, page, image, bbLowerLeftX, bbLowerLeftY, .25f*image.getWidth(), .25f*image.getHeight(), (float)(9*Math.PI/8));
(PlaceRotatedImage test testPlaceByBoundingBox)
This code draws the left and bottom lines corresponding to the left and bottom side of the given lower left bounding box coordinates and draws an image at different magnifications and angles with the constant given lower left bounding box corner.
The result looks like this:
You can find more information on the calculation of the bounding box sizes in these answers:
Calculate Bounding box coordinates from a rotated rectangle
How to get width and height of the bounding box of a rotated rectangle
How to get size of a rotated rectangle
Find the Bounding Rectangle of Rotated Rectangle
...
In my game I have a rocket sprite and at the bottom of the rocket there is an animated flame sprite , I want the flame sprite to align with the bottom of the rocket when the rocket rotates.
This is the rocket when the game starts, everything is OK:
But when i rotate the rocket the flame does not align with the rocket's bottom like this:
How can i make it align?
here is my code:
// draw rocket
rocketSprite.setRegion(AssetLoader.rocketTexture);
rocketSprite.setPosition(rocket.getX(), rocket.getY());
rocketSprite.setOrigin(rocket.getWidth() / 2, rocket.getHeight() / 2);
rocketSprite.setSize(rocket.getWidth(), rocket.getHeight());
rocketprite.setRotation(rocket.getRotation());
rocketSprite.setScale(1, 1);
rocketPodSprite.draw(game.batch);
//flame width and height
int w = 70;
int h = 20;
// randomly change scale of flame for effects
float sw = MathUtils.random(2f / 7f, 1);
float sh = MathUtils.random(0.5f, 1);
// draw flame
flameSprite.setRegion(AssetLoader.flameTexture);
flameSprite.setPosition(rocket.getX() + rocket.getWidth() / 2 - w, rocket.getY() - 15);
flameSprite.setOrigin(w, h / 2);
flameSprite.setSize(w, h);
flameSprite.setRotation(rocket.getRotation());
flameSprite.setScale(sw, sh);
flameSprite.draw(game.batch);
You need to change origin - point arround which your sprite will be rotated.
Your problem is that both rocket and flame are rotated arround their own centres however you would rather like to rotate them both arround rocket's one. Then you need to set the flame sprite origin with position of rocket center.
flameSprite.setOrigin(w, h / 2 + rocket.getHeight() / 2 + SPACE_BETWEEN_ROCKET_AND_FLAME);
As I see in your case the SPACE_BETWEEN_ROCKET_AND_FLAME has value of 15 - flame.height due to this position set:
flameSprite.setPosition(rocket.getX() + rocket.getWidth() / 2 - w, rocket.getY() - 15);
I have an image that I want to crop given the corners.
For example
I want to cut just the sudoku puzzle. I have the corners (x1, y1), (x2, y2), (x3, y3), (x4, y4).
Tried this:
javaxt.io.Image image = new javaxt.io.Image(bufferedImage);
image.setCorners((float) pointTopLeft.getX(), (float) pointTopLeft.getY(), //UL
(float) pointTopRight.getX(), (float) pointTopRight.getY(), //UR
(float) pointBottomRight.getX(), (float) pointBottomRight.getY(), //LR
(float) pointBottomLeft.getX(), (float) pointBottomLeft.getY()); //LL
But the result it returns is this (which is not what I want):
You could first skew the image by shifting the bottom corners and the top right corner - this will result in a more rectangular shape. Then you can crop the image.
I tried it with this:
Image image = new javaxt.io.Image(bufferedImage);
// skew image
image.setCorners(
// keep the upper left corner as it is
0,0, // UL
// push the upper right corner more to the bottom
image.getWidth(),20, // UR
// push the lower right corner more to the left
image.getWidth()-45,image.getHeight(), // LR
// push the lower left corner more to the right
55,image.getHeight()); // LL
// crop image
image.crop(80, 105, image.getWidth()-150, image.getHeight()-105);
And the result is this:
Hope this helps.
You should use the method image.getSubImage(x1,y1,x2,y2) so that you can crop. After this, you can skew it to the right amount.