Board index » delphi » Working out a cliprect in reverse

Working out a cliprect in reverse


2005-01-04 06:49:21 AM
delphi206
Hi all
This is the best I can explain :-)
1) I have an image control which is 100 wide and 100 high
2) The image has a picture which is 100 pixels by 100 pixels
2) I work out how large the picture would be if rotated / scaled like so
(Source for GetRotatedSize to follow)
Width is 100
Height is 100
Angle = 45
ScaleX / ScaleY = 500 (that's %)
var
S: TPoint;
begin
S := GetRotatedSize(Width, Height, Angle, ScaleX, ScaleY);
Caption := IntToStr(S.X) + ', ' + IntToStr(S.Y) + ' / ' +
FloatToStr(DIBImage1.Scale);
end;
The result is that the scaled/rotated size is 708 pixels by 708 pixels.
Obviously if I centre this scaled / rotated bitmap in my 100x100 image
control there would be some clipping.
What I want to know is, how do I reverse this process, so that I can work
out the clip rect of the original picture?
function GetRotatedSize(Width, Height: Word; Angle: Extended;
ScaleX, ScaleY: Extended): TPoint;
var
Radians: Double;
ScaleW, ScaleH: Double;
begin
Assert((Angle>= 0) and (Angle < 360));
Radians := DegToRad(-Angle);
ScaleW := Width * ScaleX / 100;
ScaleH := Height * ScaleY / 100;
Result := Point(Ceil(Abs(ScaleW * Cos(Radians)) + Abs(ScaleH *
Sin(Radians))),
Ceil(Abs(ScaleW * Sin(Radians)) + Abs(ScaleH * Cos(Radians))));
Result.X := Result.X + (Result.X mod 2);
Result.Y := Result.Y + (Result.Y mod 2);
end;
--
Pete
====
Audio compression components, DIB graphics controls, FastStrings
www.droopyeyes.com
Read or write articles on just about anything
www.HowToDoThings.com
My blog
blogs.slcdug.org/petermorris/
 
 

Re:Working out a cliprect in reverse

check out sin,cos, pythagorus thingies.
 

Re:Working out a cliprect in reverse

It was very nice book about different algorithms used for graphics
Apparently this is just plain trigonometry in space, how points are rotated
There are different methods for this
some of them:
Matrix
www.euclideanspace.com/maths/geometry/affine/aroundPoint/
and trigonometry one
www.pixelate.co.za/issues/12/articles/isoarticle/isoarticle.html
PS. It is good some time to have a math degree ;o)
--
Best regards, Serge Dosyukov
Dragon Soft
-------------------------------------------------
Check Delphi 7 ->Delphi 2005 chart www.dragonsoftru.com
Try our DS Plug-in System, now with Delphi 2005 support
www.dragonsoftru.com
"Peter Morris [Air Software Ltd]"
<XXXX@XXXXX.COM>writes
Quote
Hi all

This is the best I can explain :-)

1) I have an image control which is 100 wide and 100 high
2) The image has a picture which is 100 pixels by 100 pixels
2) I work out how large the picture would be if rotated / scaled like so

(Source for GetRotatedSize to follow)

Width is 100
Height is 100
Angle = 45
ScaleX / ScaleY = 500 (that's %)

var
S: TPoint;
begin
S := GetRotatedSize(Width, Height, Angle, ScaleX, ScaleY);
Caption := IntToStr(S.X) + ', ' + IntToStr(S.Y) + ' / ' +
FloatToStr(DIBImage1.Scale);
end;

The result is that the scaled/rotated size is 708 pixels by 708 pixels.
Obviously if I centre this scaled / rotated bitmap in my 100x100 image
control there would be some clipping.

What I want to know is, how do I reverse this process, so that I can work
out the clip rect of the original picture?

function GetRotatedSize(Width, Height: Word; Angle: Extended;
ScaleX, ScaleY: Extended): TPoint;
var
Radians: Double;
ScaleW, ScaleH: Double;
begin
Assert((Angle>= 0) and (Angle < 360));
Radians := DegToRad(-Angle);
ScaleW := Width * ScaleX / 100;
ScaleH := Height * ScaleY / 100;

Result := Point(Ceil(Abs(ScaleW * Cos(Radians)) + Abs(ScaleH *
Sin(Radians))),
Ceil(Abs(ScaleW * Sin(Radians)) + Abs(ScaleH * Cos(Radians))));

Result.X := Result.X + (Result.X mod 2);
Result.Y := Result.Y + (Result.Y mod 2);
end;


--
Pete
====
Audio compression components, DIB graphics controls, FastStrings
www.droopyeyes.com

Read or write articles on just about anything
www.HowToDoThings.com

My blog
blogs.slcdug.org/petermorris/



 

Re:Working out a cliprect in reverse

"Peter Morris [Air Software Ltd]" wrote
Quote
This is the best I can explain :-)
Peter,
I have some suggestions for solving your inversion
problems:
(1) Do not mix integer and real types unnecessarily.
I recommend converting everything to double until you
figure out how to do the inversion.
(2) Carry your angles around internally as radians. Save
the degrees for input and output with the human interface.
(3) Reduce the problem by factoring out the scaling.
Unless, I have misunderstood, it only applies to the
un-rotated orthogonal scale.
Please reply, if you would like more hints.
Best regards and wishes for a happy new year,
JohnH
 

Re:Working out a cliprect in reverse

Hi John
Quote
(1) Do not mix integer and real types unnecessarily.
I use Extended everywhere, except in my RotoZoom code which I use fixed
point integer for speed.
Quote
(2) Carry your angles around internally as radians. Save
the degrees for input and output with the human interface.
Sounds interesting, why this that?
Quote
(3) Reduce the problem by factoring out the scaling.
Unless, I have misunderstood, it only applies to the
un-rotated orthogonal scale.
It's kind of hard to explain :-)
I have a TImage which is 100 x 100, and the picture it draws is 100 x 100.
This is how it works
1) The TImage (actually TDIBImage) creates its own bitmap during .Paint
2) I then call PictureToDraw.DrawTo(Self.TemporaryDIB)
This is fine when the image is not rotated or zoomed, but when it does need
rotozooming the "DrawTo" has an intermediate step
1) Create a temp DIB of the required rotated / zoomed size
2) Loop through each pixel of the temp DIB, writing the relevant pixel from
the source
3) Finally draw the Temp DIB to the destination instead of itself
Now, when the TImage is only 100x100, and I have zoomed by 500%, obviously I
don't want to read every source pixel onto the larger pixel. I would like to
work out the size of the rect which would be visible so that the RotoZoom
only works within that area.
Zooming would be easy enough to work out, the size of the rectangle read
from the source would just be Width * (100 / Scale) as opposed to Width *
(Scale / 100), but when you factor in rotation you obviously see some extra
pixels because they have been rotated into view.
--
Pete
====
Audio compression components, DIB graphics controls, FastStrings
www.droopyeyes.com
Read or write articles on just about anything
www.HowToDoThings.com
My blog
blogs.slcdug.org/petermorris/
 

Re:Working out a cliprect in reverse

"Peter Morris [Air Software Ltd]" wrote
Quote
>(1) Do not mix integer and real types unnecessarily.
I use Extended everywhere,
Peter,
Double (being 2^3 bytes) fits storage better than
extended and is faster to store and read.
Double is very precise. (It can represent the distance
from Earth to Sun to 1/2 a micrometer.)
Quote
except in my RotoZoom code which I use fixed point
integer for speed.
Does this make it faster? I suspect that cleaning
up the code will give more improvement.
Quote
>(2) Carry your angles around internally as radians.
>Save the degrees for input and output with the
>human interface.
Sounds interesting, why this that?
To avoid extra conversions and simplify the algebra.
Quote
>(3) Reduce the problem by factoring out the scaling.
>Unless, I have misunderstood, it only applies to the
>un-rotated orthogonal scale.
It's kind of hard to explain :-)
Then maybe it is time to look at the fundamentals. <g>
If I understood your original, inversion problem correctly,
then the forward transformation can be simplified to
w = x*cos(a) + y*sin(a)
h = x*sin(a) + y*cos(a)
which are a pair of linear equations. Thus, given w, h,
and a, they can be solved for x and y solved by first
removing x from the pair and finding y and then
substituting for y in either equation to solve for x.
Regards, JohnH
 

Re:Working out a cliprect in reverse

Quote
Double (being 2^3 bytes) fits storage better than
extended and is faster to store and read.
I'll give Double a try then.
Quote
Double is very precise. (It can represent the distance
from Earth to Sun to 1/2 a micrometer.)
Hmm, but what if you love someone to the sun and back? :-)
Quote
Does this make it faster? I suspect that cleaning
up the code will give more improvement.
This makes it *much* faster. If you trust me enough to run an exe, take a
look in attachments group for a small demo.
Quote
If I understood your original, inversion problem correctly,
then the forward transformation can be simplified to
w = x*cos(a) + y*sin(a)
h = x*sin(a) + y*cos(a)
which are a pair of linear equations. Thus, given w, h,
and a, they can be solved for x and y solved by first
removing x from the pair and finding y and then
substituting for y in either equation to solve for x.
I'll try making sense of this when my brain is clearer, thanks :-)
--
Pete
====
Audio compression components, DIB graphics controls, FastStrings
www.droopyeyes.com
Read or write articles on just about anything
www.HowToDoThings.com
My blog
blogs.slcdug.org/petermorris/
 

Re:Working out a cliprect in reverse

On Tue, 4 Jan 2005 10:55:01 -0000, "Peter Morris [Air Software Ltd]"
<XXXX@XXXXX.COM>writes:
Quote
Now, when the TImage is only 100x100, and I have zoomed by 500%, obviously I
don't want to read every source pixel onto the larger pixel. I would like to
work out the size of the rect which would be visible so that the RotoZoom
only works within that area.
Just to make sure I didn't confuse things here. In the rotozoomer, you
only go over the destination bitmap, reversemapping their position to
the source image and copy that pixel to the destination, right?
(source pixel interpolation aside)
- Asbjørn