FAQFAQ   SearchSearch   MemberlistMemberlist   RegisterRegister   ProfileProfile   Log inLog in 


Rotate a bitmap by an arbitrary angle

Post new topic   Reply to topic    discuss.visual-prolog.com Forum Index -> Visual Prolog
View previous topic :: View next topic  
Author Message
Harrison Pratt



Des Moines, Iowa USA
Joined: 05 Nov 2000
Posts: 312

PostPosted: 19 Mar 2017 17:16    Post subject: Rotate a bitmap by an arbitrary angle Reply with quote

I am just starting to explore GDI+ and the depth of my understanding is very shallow. By way of exploration, I decided to tackle rotating a resource bitmap by an arbitrary angle and still have not fully absorbed how pointers, handles, bitmapIDs, and actual images are managed by VP and GDI.

My little test code below is intended to load a bitmap, draw it, rotate it 90 degrees, draw that rotated bitmap, then rotate a copy of the original bitmap 33.3 degrees and draw that bitmap. I am stumped on how to handle the last part of the test--the first two parts are simply to verify that I can draw something.

predicates
    onPaint : window::paintResponder.
clauses
        onPaint( _Source, _Rectangle, GDI):-
            Pnt1 = pnt(100,100),
            Pnt2 = pnt(150,100),
            Pnt3 = pnt(200,100),
            Angle = 33.3,  % angle to rotate bitmap below

            % Bitmap name in resources = "BoatStbdTack"
            PicB = vpi::pictGetFromRes( resourceIdentifiers::idb_boatstbdtack ),   % returns a PICTURE (a POINTER to the the bitmap)
            GDI:pictDraw( PicB, Pnt1, rop_SrcAnd ),  % operates on the POINTER to the picture

            PtrB90 = vpi::pictRotate(PicB,pictRotate_90deg ),  % counter-clockwise rotation, only in 90 degree steps
            GDI:pictDraw( PtrB90, Pnt2, rop_SrcAnd ),

            /*
                    This is where I am stumped.

                    How can I create BMP_ToROTATE (an actual bitmap) to rotate using rotateImage/2 below ?

                    Perhaps rotateImage/2 should be modified to work with pictures (pointers) instead of actual bitmaps ...
            */


            NewRotBMP = rotateImage(  BMP_ToROTATE, Angle ),
            GDI:pictDraw( NewRotBMP ,Pnt3,rop_SrcAnd),
            succeed.

The predicate to rotate a bitmap is below:

class predicates
    rotateImage : (  bitmap, real AngleToRotate ) -> bitmap RotatedBMP.
clauses
    rotateImage(  BMP, Angle ) = RotatedBMP :-
        G = graphics::createFromImage( BMP ),    % create new graphics canvas
        % move rotation point to center of image
        G:translateTransform( BMP:width/2, BMP:height /2 ),
        % rotate the graphics
        G:rotateTransform( Angle ),
        % move the image back
        G:translateTransform( - BMP:width/2, - BMP:height/2 ),
        % create bitmap from rotated graphics
        RotatedBMP = bitmap::createFromGraphics( BMP:width, BMP:height, G).

Back to top
View user's profile Send private message
Paul Cerkez



Lexington Park MD, USA
Joined: 06 Mar 2000
Posts: 619

PostPosted: 19 Mar 2017 19:48    Post subject: Reply with quote

Harrison,
I did exactly this a few years back. let me see if I can find my code.

P.

_________________
AI Rules!
P.
Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 19 Mar 2017 20:23    Post subject: Reply with quote

Have you examined the GDI+ example that comes with Visual Prolog?

Also you didn't tell what happened (exception, nothing, wrong result, ...).

_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
Harrison Pratt



Des Moines, Iowa USA
Joined: 05 Nov 2000
Posts: 312

PostPosted: 20 Mar 2017 3:17    Post subject: Reply with quote

I did work through the GDI+ example and had no problems there. I can draw lines and shapes without problem, and the test code I submitted draws the resource bit map normally and rotated without problem. I also remembered to call

appGDI::appGdiStart()

in the taskWindow:onShow/2 clause.

My confusion is with how to obtain a 'bitmap' structure to pass to this line of code:

NewRotBMP = rotateImage(  BmpToRotate, Angle ),

Depending upon which GDI-related or VIP predicates I use to retrieve what I expect (hope) is a bitmap, I get compiler error 504, where XXX is 'picture' or 'bitmapID' etc.,

e504      The expression has type 'XXX', which is incompatible with the type 'bitmap'   DrawingForm.pro   Test001_PACK\

For example, if I use BmpToRotate = vpi::pictToBitmap(PicB) to get a bitmap to rotate, the error is The expression has type '::handle', which is incompatible with the type 'bitmap'

And if I use Type BmpToRotate = PicB to get deine the bitmap, the error is The expression has type 'vpiDomains::picture', which is incompatible with the type 'bitmap'

I am looking for love (bitmaps) in all the wrong places! Confused
Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 21 Mar 2017 13:39    Post subject: Reply with quote

If your purpose is to draw the bitmap in the window somewhere, then it seems silly first to convert it from GDI to GDI+ (and then manipulate it) and then convert it again to draw it in GDI.

I think it is better to "stay" in GDI+.

Besides this you have misunderstood how a graphics and bitmaps works together. A graphics created on an image will allow you to draw in that image, rotating and translating will affect subsequent drawing operations, but will not change the image at all.

Furthermore an image created from a graphics is an empty image that just inherits settings/properties from the graphics.

So the correct way to create a rotated bitmap is first to create an empty bitmap, and then a graphics on that image, then perform rotations and translations and then finally draw the original bitmap. Than way the original bitmap will be drawn rotated and translated into the new bitmap.

clauses
    onPaint(_Source, _Rectangle, GDI) :-
        BitMapOrig = bitmap::createFromResID(mainExe::getCurrentHinstance(), vpiDomains::application_icon, 32, 32),
        % create a rotated bitmap
        BitMapRot = bitmap::create(32, 32, gdiplus_native::pixelFormat32bppPARGB),
        G2 = graphics::createFromImage(BitMapRot),
        G2:translateTransform(16, 16),
        G2:rotateTransform(30),
        G2:drawImageI(BitMapOrig, -16, -16),
        % Now do the drawing
        HCD = GDI:getNativeGraphicContext(Release),
        Graphics = graphics::createFromHDC(HCD),
        Graphics:drawImageI(BitMapOrig, gdiplus::pointI(50, 50)),
        Graphics:drawImageI(BitMapRot, gdiplus::pointI(150, 50)),
        GDI:releaseNativeGraphicContext(HCD, Release).

It will of course be more efficient not to create the intermediate bitmap at all but to rotate and translate the window graphics instead. But it can be quite challenging to keep track of translations and rotations.

If you try this approach it will be a good idea to save the original transformation so that you can reset it back to normal between transformation steps.

By the way it is much simpler to startup and shutdown GDI+ in the main run predicate:

clauses
    run() :-
        Token = gdiplus::startUp(),
        TaskWindow = taskWindow::new(),
        TaskWindow:show(),
        gdiplus::shutDown(Token).


_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
Harrison Pratt



Des Moines, Iowa USA
Joined: 05 Nov 2000
Posts: 312

PostPosted: 21 Mar 2017 20:28    Post subject: Reply with quote

Thomas,

Thank you for your clarification -- I greatly appreciate the time that it took you to get me started down the correct way of thinking! My initial goal was to stay in GDI+, but I became lost wandering in the forest of ancient classes (no criticism intended).

Thanks for the hint on initializing the application in the run/0 clause. That tidy approach has many uses.

I wonder if cachedBitmap might offer some performance benefits, but I'm a long way from needing to add that complexity now.

My toy GDI+ learning application is to create a little sailboat racing tactical simulator with top-views of boats on port or starboard tack and initially just show how wind shifts affect their relationship to a windward mark of the course. Images of boats on each tack (P&S) would move across the screen and have their path and rotation on the screen (compass heading) changed as the wind shifted. Of course, each boat (object) would have attributes such as maximum speed (proportional to square root of waterline length), time required to change tack, time required to resume full speed after a tack, etc. -- elaborations to be added once I understand the graphic display.

Very Happy
Back to top
View user's profile Send private message
Harrison Pratt



Des Moines, Iowa USA
Joined: 05 Nov 2000
Posts: 312

PostPosted: 21 Mar 2017 20:41    Post subject: Reply with quote

I don't understand how to use optional{image} in this context. The IDE generates a compiler error on this line of code:

BitMapOrig = bitmap::createFromResID( mainExe::getCurrentHinstance(), vpiDomains::application_icon, 32, 32 ),

e504 The expression has type 'bitmap', which is incompatible with the type 'core::optional{image}'
Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 22 Mar 2017 21:17    Post subject: Reply with quote

I guess you are passing BitMapOrig to some predicate that takes an optional{image} as argument.

An optional{image} is either some(<<Image>>) or none.

So that predicate should have some(BitMapOrig) as argument.

_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
Harrison Pratt



Des Moines, Iowa USA
Joined: 05 Nov 2000
Posts: 312

PostPosted: 22 Mar 2017 22:31    Post subject: Reply with quote

Sorry for my ambiguity. The compiler error occured when I pasted the sample code you provided earlier into the onPaint/3 clause for my test form:

        onPaint( _Source, _Rectangle, GDI):-
                /* ERROR HERE: */ BitMapOrig = bitmap::createFromResID(mainExe::getCurrentHinstance(), vpiDomains::application_icon, 32, 32),
                % create a rotated bitmap
                BitMapRot = bitmap::create(32, 32, gdiplus_native::pixelFormat32bppPARGB),
                G2 = graphics::createFromImage(BitMapRot),
                G2:translateTransform(16, 16),
                G2:rotateTransform(30),
                G2:drawImageI(BitMapOrig, -16, -16),
                % Now do the drawing
                ...

Back to top
View user's profile Send private message
Thomas Linder Puls



Copenhagen, Denmark
Joined: 28 Feb 2000
Posts: 3124

PostPosted: 23 Mar 2017 9:10    Post subject: Reply with quote

Sorry, that is my fault. I didn't run the code in Vip 7.5 but in our current version.

In Vip 7.5 drawImageI takes an optional{image} as argument. (Which is very silly because who will ever draw none image, so in the upcoming release drawImageI takes an image (non-optional) as argument).

Anyways, in Vip 7.5 you will have to wrap the images in some to kame them optional{image}. For example like this:

predicates
    onPaint : window::paintResponder.
clauses
    onPaint(_Source, _Rectangle, GDI) :-
        BitMapOrigOpt = some(bitmap::createFromResID(mainExe::getCurrentHinstance(), vpiDomains::application_icon, 32, 32)),
        % create a rotated bitmap
        BitMapRot = bitmap::create(32, 32, gdiplus_native::pixelFormat32bppPARGB),
        G2 = graphics::createFromImage(BitMapRot),
        G2:translateTransform(16, 16),
        G2:rotateTransform(30),
        G2:drawImageI(BitMapOrigOpt, -16, -16),
        % Now do the drawing
        HCD = GDI:getNativeGraphicContext(Release),
        Graphics = graphics::createFromHDC(HCD),
        Graphics:drawImageI(BitMapOrigOpt, gdiplus::pointI(50, 50)),
        Graphics:drawImageI(some(BitMapRot), gdiplus::pointI(150, 50)),
        GDI:releaseNativeGraphicContext(HCD, Release).


_________________
Regards Thomas Linder Puls
Prolog Development Center
Back to top
View user's profile Send private message
Harrison Pratt



Des Moines, Iowa USA
Joined: 05 Nov 2000
Posts: 312

PostPosted: 23 Mar 2017 12:30    Post subject: Reply with quote

Ahhh ... now I understand.

Thank you!
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic    discuss.visual-prolog.com Forum Index -> Visual Prolog All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You cannot attach files in this forum
You can download files in this forum