I'm trying rotate a rectangle around its center. The rotation is being drawn to a canvas using the GraphicsContext ie gc. Here is my draw code.
gc.save();
gc.translate(center.x, center.y);
gc.rotate(this.angle);
gc.strokeRect(0,0, this.width, this.height);
gc.restore();
This moves the rectangle to its center but then it rotates the rectangle around its top left point. I tried subtracting half the length and width of the sides but that just made it fly all over the place. I suck at math maybe someone here who is better can show me what I'm doing wrong.
I also have stored all four points (corners) of the rectangle if that information is needed.
Thanks,
Joe
A rotation around a specified point needs to be composed from translate transformations and rotations around the origin as follows:
Use translation to move the center of the rotation to the origin.
rotate around the origin
use inverse translation to the first translation
The third part is missing from your code.
Example
#Override
public void start(Stage primaryStage) throws Exception {
Canvas canvas = new Canvas(400, 400);
double x = 50;
double y = 100;
double width = 100;
double height = 200;
GraphicsContext gc = canvas.getGraphicsContext2D();
double rotationCenterX = (x + width) / 2;
double rotationCenterY = (y + height) / 2;
gc.save();
gc.translate(rotationCenterX, rotationCenterY);
gc.rotate(45);
gc.translate(-rotationCenterX, -rotationCenterY);
gc.fillRect(0, 0, width, height);
gc.restore();
Scene scene = new Scene(new Group(canvas));
primaryStage.setScene(scene);
primaryStage.show();
}
You could also simply use a Rotate with a specified pivot to achieve the desired effect:
#Override
public void start(Stage primaryStage) throws Exception {
Canvas canvas = new Canvas(400, 400);
double x = 50;
double y = 100;
double width = 100;
double height = 200;
GraphicsContext gc = canvas.getGraphicsContext2D();
double rotationCenterX = (x + width) / 2;
double rotationCenterY = (y + height) / 2;
gc.save();
gc.transform(new Affine(new Rotate(45, rotationCenterX, rotationCenterY)));
gc.fillRect(0, 0, width, height);
gc.restore();
Scene scene = new Scene(new Group(canvas));
primaryStage.setScene(scene);
primaryStage.show();
}
It's just so simple, like below.
Rectangle rect = new Reactangle(20, 20, 100, 50);
rect.setRotate(30); //rotate the rectangle around its center by 30 degrees.
Related
Iam trying to add some Labels to a GridPane.
Those Labels contain ImageViews which contain some Images.
My images are .png-images and are 50 x 50 pixels big.
If my GridPane is getting to big to display it on my screen, I want to resize my Images. Iam trying this with the methods setFitWidth and setFitHeight.
Snipped:
#Override
public void start(Stage stage) {
GridPane gridPane = new GridPane();
int ySize = 5;
int xSize = 5;
int imageSize = 25;
for(int i=0 ; i<ySize ; i++) {
for(int j=0 ; j<xSize ; j++) {
ImageView imageView = new ImageView(new Image(getClass().getResourceAsStream("path.png")));
imageView.setFitWidth(imageSize);
imageView.setFitHeight(imageSize);
Label label = new Label();
label.setGraphic(imageView);
gridPane.add(label, i, j);
}
}
stage.setScene(new Scene(gridPane));
stage.show();
}
The output looks fine:
However, if imageSize is getting to small, for example 10, a horicontal spacing appears between the rows:
Is there any way to remove this? I tried to set the label sizes max-properties:
label.setMaxHeight(imageSize);
label.setMaxWidth(imageSize);
with no effect.
Is there any way to remove the spacing? Is it because the images are .png's?
Thank you
I have a QGraphicsView subclass, holding a QGraphicsScene subclass, inside a QWidget.
The QGraphicsScene has an actual drawing rectangle with top let corner at (0,0) (so the scene really has a QRectF(-x,-y,w,h) of values irrelevant to the problem).
On startup, actually in the showEvent of the widget, I set the size of the scene to fit the custom sized rectangle. That also centers it.
What I would like, is to match the (0,0) point of the scene to the top left of the view, on start.
Unlike other questions with the same title, I actually need to move the view, not the items inside the scene.
Image 1: actual start, image 2: desired
I am trying:
void MyWidget::showEvent(QShowEvent *event)
{
static bool startUp = true;
if(startUp)
{
QSizeF sz = m_scene->getActualSize();
ui->graphicsView->fitInView(QRectF(0, 0, sz.width(), sz.height()), Qt::KeepAspectRatio);
QPointF zero = ui->graphicsView->mapFromScene(QPointF(0,0));
ui->graphicsView->translate(-zero.x(), -zero.y()); // or positive
startUp = false;
}
QWidget::showEvent(event);
}
note: I use the fitInView to get the desired zoom - and it also brings the desired rectangle in focus - but centered in the view.
I also tried
void GraphicsView::alignToZero()
{
QPointF zero = this->mapFromScene(QPointF(0,0));
this->scrollContentsBy(-zero.x(), -zero.y());
}
void MyWidget::showEvent(QShowEvent *event)
{
static bool startUp = true;
if(startUp)
{
QSizeF sz = m_scene->getActualSize();
ui->graphicsView->fitInView(QRectF(0, 0, sz.width(), sz.height()), Qt::KeepAspectRatio);
ui->graphicsView->alignToZero();
startUp = false;
}
QWidget::showEvent(event);
}
Still no result.
Also tried
void MyWidget::showEvent(QShowEvent *event)
{
static bool startUp = true;
if(startUp)
{
QSizeF sz = m_scene->getActualSize();
ui->graphicsView->fitInView(QRectF(0, 0, sz.width(), sz.height()), Qt::KeepAspectRatio);
QPointF zero = ui->graphicsView->mapFromScene(QPointF(0,0));
//ui->graphicsView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
ui->graphicsView->horizontalScrollBar()->setValue(zero.x());
ui->graphicsView->verticalScrollBar()->setValue(zero.y());
startUp = false;
}
QWidget::showEvent(event);
}
This, with or without the alignment setting (which I think may have unwanted effects elsewhere), moves the view... too far.
If I understand your question correctly, to achieve desired effect you can use method
QGraphicsView::setAlignment(Qt::Alignment alignment):
ui->graphicsView->setAlignment( Qt::AlignTop | Qt::AlignLeft );
Which is commented in your code.
This method with those arguments aligns view top-left, you don't have to move or fit anything.
While there must be a better way... I figured out a way to get my 0's aligned by doing fitInView twice:
void MyWidget::showEvent(QShowEvent *event)
{
static bool startUp = true;
if(startUp)
{
QSizeF sz = m_scene->getActualSize();
// First I do a normal `fitInView` that centers the rectangle
ui->graphicsView->fitInView(QRectF(0, 0, sz.width(), sz.height()), Qt::KeepAspectRatio);
// Then, knowing the shift, I fit it again adding twice the shift to the size.
QPointF zero = ui->graphicsView->mapToScene(QPoint(0,0));
ui->graphicsView->fitInView(QRectF(0, 0, sz.width() - 2 * zero.x(), sz.height() - 2 * zero.y()), Qt::KeepAspectRatio);
startUp = false;
}
QWidget::showEvent(event);
}
I have a problem to draw this image (below link) I had his in the middle of flow pane but only half of this! How to draw full image>?
http://s16.postimg.org/lrus832dx/Capture2.png
http://s27.postimg.org/hsujjp1s3/Capture1.png
Ok, I think I understand your problem now. I suggest you to use a GridPane instead, then you can do it this way:
#Override
public void start(Stage primaryStage) {
GridPane root = new GridPane();
int rows = 2;
int columns = 2;
int rectangleWidth = 50;
int rectangleHeight = 50;
root.setMaxSize(rectangleWidth*columns, rectangleHeight*rows);
for(int row = 0; row < rows; row++)
{
for(int col= 0; col< columns; col++)
{
Rectangle rectangle = new Rectangle(rectangleWidth, rectangleHeight);
root.add(rectangle, col, row);
if(row % 2 == 0)
{
rectangle.setFill(col % 2 == 0 ? Color.ORANGE : Color.BLACK);
}
else
{
rectangle.setFill(col % 2 != 0 ? Color.ORANGE : Color.BLACK);
}
}
}
Scene scene = new Scene(new StackPane(root), 700, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
We need to wrap the GridPane containing the Rectangles in a StackPane to center it in its parent.
I have figured out how to make a circle move randomly, but now I want there to be 100 circles, but can't figure out how to add them, HELP!
float my_num = 10;
float n = random(5, 60);
void setup() {
size(500, 500);
background(0);
fill(255);
noStroke();
smooth();
rectMode(CENTER);
}
void draw() {
background(0);
translate(width * noise(my_num + 80), height * noise(my_num + 100));
rotate(10 * noise(my_num + 40));
ellipse(n, n, n, n);
my_num = my_num + 0.02;
}
Sounds like you should create a Circle class that contains the position, size, color, etc of a circle.
Then create an ArrayList or array that contains 100 Circles, and loop through them whenever you want to update or draw those circles.
Recommended reading: http://staticvoidgames.com/tutorials/objects/fireworks
I have to do some projet to draw regular polygon with Canvas in JavaFX, and I have doubt how to design a circle with canvas using GraphicsContext
I have this point class containing the two axes (x, y)
public class Point2D {
private float mX;
private float mY;
public Point2D () {
this (0,0);
}
public Point2D (float x, float y) {
mX = x;
mY = y;
}
public float getX() {
return mX;
}
public float getY() {
return mY;
}
}
And I have this circle Class and I have doubt to made the method public void drawCircle(GraphicsContext gc)
public class Circle{
private Point2D mCenter;
private Color color;
private float mRadius;
public Circle (Point2D center, Color color, float radius ) {
this.mCenter = center;
this.color = color;
this.mRadius = radius;
}
public void drawCircle(GraphicsContext gc) { // My Doubt is here
Canvas canvas = new Canvas();
gc = canvas .getGraphicsContext2D();
gc.setFill(Color.WHITE);
gc.setStroke(Color.BLACK);
}
}
In Main JavaFX
public class PaintGeometricoFX extends Application {
private BorderPane root;
#Override
public void start(Stage primaryStage) {
Point2D p = new Point2D(0, 0);
Float radius = 4.0f;
Circle circle = new Circle(p.getX(), p.getY(),Color.BLACK,radius)
Canvas canvas = new Canvas();
GraphicsContext gc = imagem.getGraphicsContext2D();
circle.drawCircle(gc);
root.setCenter(canvas);
Scene scene = new Scene(root, 1152, 800);
primaryStage.setTitle("PAINT");
primaryStage.setResizable(false);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Stroking:
getGraphicsContext2D().strokeOval(center.x-radius, center.y-radius, radius * 2, radius * 2);
Filling:
getGraphicsContext2D().fillOval(center.x-radius, center.y-radius, radius * 2, radius * 2);
Note the 3rd and 4th parameters are diameters not radii. I had a discrepancy between ScalaFx and the correct ScalaJs output. But I checked the JavaFx documentation and it works the same:
fillOval
public void fillOval(double x,
double y,
double w,
double h)
Fills an oval using the current fill paint.
This method will be affected by any of the global common or fill attributes as specified in the Rendering Attributes Table.
Parameters:
x - the X coordinate of the upper left bound of the oval.
y - the Y coordinate of the upper left bound of the oval.
w - the width at the center of the oval.
h - the height at the center of the oval.
Stroking:
getGraphicsContext2D().strokeOval(center.x-radius, center.y-radius, radius, radius);
Filling:
getGraphicsContext2D().fillOval(center.x-radius, center.y-radius, radius, radius);