B4J Question How to Get the Bounds of a Rotated Node

xulihang

Active Member
Licensed User
Longtime User
1696771854121.png


I am creating an image editor and I need to take a snapshot of the controls. But snapshot cannot work in a large resolution so I decided to use BitmapCreator.

The problem I am facing is that if a node is rotated, I cannot accurately draw it in the BitmapCreator.

I know I need to know the exact bounds of the node after rotation. I use the following code to get the rotated rectangle but it is a bit away from the real position. I would like to know the correct way to do this.

My test project is attatched.

B4X:
Private Sub Button1_MouseClicked (EventData As MouseEvent)
    If CheckBox1.Checked Then
        Dim img As Image = Pane1.Snapshot2(fx.Colors.Transparent)
        ImageView1.SetImage(img)
    Else
        Dim bc As BitmapCreator
        bc.Initialize(Pane1.Width,Pane1.Height)
        Dim r1 As B4XRect
        r1.Initialize(Label1.Left,Label1.Top,Label1.Left+Label1.Width,Label1.Top+Label1.Height)
        bc.DrawBitmap(Label1.Snapshot2(fx.Colors.Transparent),r1,False)
        Dim r2 As B4XRect
        r2.Initialize(Label2.Left,Label2.Top,Label2.Left+Label2.Width,Label2.Top+Label2.Height)
        Dim rotatedRect As B4XRect = getRotatedRect(315,r2)
        bc.DrawBitmap(Label2.Snapshot2(fx.Colors.Transparent),rotatedRect,False)
        ImageView1.SetImage(bc.Bitmap)
    End If
End Sub

Sub getRotatedRect(degree As Double,r As B4XRect) As B4XRect
    Dim Points As List = getRotatedPoints(degree,r)
    Dim Point1,Point2,Point3,Point4 As Point2D
    Point1=Points.Get(0)
    Point2=Points.Get(1)
    Point3=Points.Get(2)
    Point4=Points.Get(3)
    Dim left,top,right,bottom As Double
    left=Point1.X
    top=Point1.Y
    For Each point As Point2D In Array(Point1,Point2,Point3,Point4)
        left=Min(point.X,left)
        top=Min(point.Y,top)
        right=Max(point.X,right)
        bottom=Max(point.Y,bottom)
    Next
    Dim rotatedRect As B4XRect
    rotatedRect.Initialize(left,top,right,bottom)
    Return rotatedRect
End Sub

private Sub getRotatedPoints(degree As Double,r As B4XRect) As List
    Dim center As Point2D
    center.Initialize
    center.X=r.CenterX
    center.Y=r.CenterY
    Dim Point1,Point2,Point3,Point4 As Point2D
    Point1=CalculateRotatedPosition(degree,center.X,center.Y,r.Left,r.Top)
    Point2=CalculateRotatedPosition(degree,center.X,center.Y,r.Left+r.width,r.Top)
    Point3=CalculateRotatedPosition(degree,center.X,center.Y,r.Left+r.width,r.Top+r.height)
    Point4=CalculateRotatedPosition(degree,center.X,center.Y,r.Left,r.Top+r.height)
    Return Array(Point1,Point2,Point3,Point4)
End Sub

private Sub CalculateRotatedPosition(degree As Double,pivotx As Double,pivoty As Double,x As Double,y As Double) As Point2D
    Dim rotate As JavaObject
    rotate.InitializeNewInstance("javafx.scene.transform.Rotate",Array(degree,pivotx,pivoty))
    Dim point2dJO As JavaObject = rotate.RunMethod("transform",Array(x,y))
    Dim point As Point2D
    point.Initialize
    point.X=point2dJO.RunMethod("getX",Null)
    point.Y=point2dJO.RunMethod("getY",Null)
    Return point
End Sub
 

Attachments

  • Node2Image.zip
    3.2 KB · Views: 54

stevel05

Expert
Licensed User
Longtime User
I was going to suggest using the getBoundsInParent method of node as in:

B4X:
Sub getRotatedRect2(V As B4XView) As B4XRect
    Dim B As JavaObject = V.As(JavaObject).RunMethod("getBoundsInParent",Null)
    Dim r As B4XRect
    r.Initialize(B.RunMethod("getMinX",Null),B.RunMethod("getMinY",Null),B.RunMethod("getMaxX",Null),B.RunMethod("getMaxY",Null))
    Return R
End Sub

but it appears to return exactly the same values as your calculation.

R1 (134.03806, 9.038059, 225.96194, 100.961945)

R2 (134.03806, 9.038059, 225.96194, 100.961945)

It does lose a little precision converted to float. The Bounds returns the values as doubles as:
(BoundingBox) BoundingBox [minX:134.03805541992188, minY:9.03805923461914, minZ:0.0, width:91.92388916015625, height:91.92388916015625, depth:0.0, maxX:225.96194458007812, maxY:100.96194839477539, maxZ:0.0]

Which is hardly enough difference to matter.

Which makes me wonder if the snapshot is accurate, or possibly scaling somewhere along the line.
 

Attachments

  • Node2Image2.zip
    3.2 KB · Views: 46
Upvote 0

xulihang

Active Member
Licensed User
Longtime User
I use the snapshot's width and height to calculate the rectangle's right and bottom. The result turns out okay.

B4X:
right = left + snapshot.Width
bottom = top + snapshot.Height
 

Attachments

  • Node2Image.zip
    3.3 KB · Views: 42
Upvote 0

stevel05

Expert
Licensed User
Longtime User
So the snapshot width and height are rounded. I guess that makes sense, but just enough to throw off the calculations.
 
Upvote 0
Top