Rotating Rectangular Dots Individually Distorts the Rectangle

enter image description here I am trying to rotate a rectangle by rotating its points using this code

var dx,dy:real; rotp:Tpoint; begin dx := (CenterPoint.Y * Sin(angle)) - (CenterPoint.X * Cos(angle)) + CenterPoint.X; dy := -(CenterPoint.X * Sin(angle)) - (CenterPoint.Y * Cos(angle)) + CenterPoint.Y; rotP.X := round((point.X * Cos(angle)) - (point.Y * Sin(angle)) + dx); rotP.Y := round((point.X * Sin(angle)) + (point.Y * Cos(angle)) + dy); result:= rotP; end; 

but the round function makes you distort the rectangle, does anyone have any ideas how to overcome this?

I attached the image, white dots are the points that I rotate around the center point, I am sure that the image rotates well, so the white dots should be identical to the corners of the image.

+7
source share
3 answers

The only way I can see that this approach will fail is to transform each point around the perimeter. If you do this, do not do this. Transform corners and draw lines between each corner using graphic primitives.

Update: Your comment gives away the game. You rotate many times and accumulate errors every time you digitize, converting to an integer. Do this by storing your coordinates as double precision values ​​and just convert to an integer on demand when you need to draw.

In fact, if I were you, I would consider your basic data as a position and angle, both stored in double precision. I would not store the coordinates of the corners at all. I would keep the position (center or one of the corners) and the angle of orientation (relative to a fixed system of global axes). This way you will always draw a true rectangle. At each integration step, increase the position and orientation, if necessary, and then calculate the position of the corners from the master data. Do it this way and you will never suffer from distortion of your form.

+7
source

Floating point calculations, especially those with trigonometric functions, are always error prone due to the limited resolution of floating point variables. You could increase the accuracy of the calculations when you multiply the difference of coordinates by a trigonometric function instead of multiplying the coordinates and subtracting the results. You can try this code (assuming the angle is in radians and math.pas is used):

 var dx,dy,ca,sa:Extended; rotp:Tpoint; begin SinCos(angle, sa, ca); dx := point.x - CenterPoint.X; dy := point.y - CenterPoint.Y; result.X := CenterPoint.X + round(dx*ca - dy*sa); result.Y := CenterPoint.Y + round(dx*sa + dy*ca); end; 

Update: And, according to the edited David, you should not use incremental rotations, as this will increase the rounding error.

+4
source
 type TRectangle = record A, B, C, D: TPoint; end; var Rectangle, // master rect TurnedRectangle: TRectangle; // turned rect ... procedure RotateRectangle; begin TurnedRectangle.A := RotatePoint(Rectangle.A); ... DrawRectangle end function RotatePoint(Point: TPoint): TPoint; var dx, dy: Real; rotp: TPoint; begin dx := (CenterPoint.Y * Sin(angle)) - (CenterPoint.X * Cos(angle)) + CenterPoint.X; dy := -(CenterPoint.X * Sin(angle)) - (CenterPoint.Y * Cos(angle)) + CenterPoint.Y; rotP.X := Round((Point.X * Cos(angle)) - (point.Y * Sin(angle)) + dx); rotP.Y := Round((Point.X * Sin(angle)) + (point.Y * Cos(angle)) + dy); result:= rotP; end; procedure DrawRectangle; begin Canvas.Polygon([TurnedRectangle.A, TurnedRectangle.B, TurnedRectangle.C, TurnedRectangle.D]); end; 
+1
source

All Articles