Tagged: Image; Scaling; Canvas; Drawing
July 11, 2019 at 10:07 pm #16248
While starting on a new project I encountered an issue which I, sadly, and over the course of more hours than I care to admit, have been unable to solve. So here it is: I have found that while up-scaling or down-scaling an image, the relative position of a co-ordinant or pixel changes unevenly, such that at the top-right of the image the relative position changes close to a factor of zero. But increases as you get closer to the bottom-left of the image. This uneven scaling makes it quite difficult to maintain the relative position of the image while scaling, which is the purpose I am using it for. This uneven scaling also makes more novel approaches such as changing the offset of the image by adding or subtracting however many pixels in width/height it increases or decreases unusable, as this is different across the image. I have included a sample image and code to help illustrate what I mean by this. Any help would be much appreciated, bonus points for a solution which supports images of varying dimensions.Monkey1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889Namespace MainWindow'Library Imports#Import "<std>"#Import "<mojo>"#Import "<mojox>"'Images#Import "sample.png"Using std..Using mojo..Using mojox..Global ImageSample:Image = Image.Load("asset::sample.png")Global windowWidth:Int = 1000Global windowHeight:Int = 700Global xOffset:IntGlobal yOffset:IntGlobal selX:IntGlobal selY:IntGlobal zoom:Float = 0.5Global debugOverlay:Bool = TrueClass MainWindow Extends WindowMethod New()Super.New("Image Scaling",windowWidth,windowHeight,WindowFlags.Center)EndMethod OnRender(canvas:Canvas) OverrideApp.RequestRender()selX = (Mouse.X - xOffset)selY = (Mouse.Y - yOffset)If Keyboard.KeyDown(Key.Z) Thenzoom -= 0.01'Increase offsetsxOffset += 0yOffset += 0EndifIf Keyboard.KeyDown(Key.X) Thenzoom += 0.01'Decrease offsetsxOffset -= 0yOffset -= 0EndifIf Keyboard.KeyDown(Key.W) Then yOffset += 3*(1/zoom)If Keyboard.KeyDown(Key.S) Then yOffset -= 3*(1/zoom)If Keyboard.KeyDown(Key.A) Then xOffset += 3*(1/zoom)If Keyboard.KeyDown(Key.D) Then xOffset -= 3*(1/zoom)canvas.Alpha = 1canvas.DrawImage(ImageSample,xOffset,yOffset,0,zoom,zoom)If Keyboard.KeyHit(Key.R) Then debugOverlay = Not debugOverlayIf debugOverlay = True Thencanvas.Alpha = 0.5canvas.DrawImage(ImageSample,xOffset,yOffset,0,zoom+0.01,zoom+0.01)canvas.Alpha = 1Endif'Debug stuffcanvas.DrawRect(windowWidth/2,windowHeight/2,2,2)canvas.DrawText(xOffset+","+yOffset,0,0)canvas.DrawText(selX+","+selY,0,16)canvas.DrawText(zoom,0,48)If Keyboard.KeyHit(Key.Escape) Then App.Terminate()EndEndFunction Main()New AppInstanceNew MainWindowApp.Run()End
Attachments:July 12, 2019 at 8:05 am #16253
I have an idea of what’s happening, but I don’t know exactly what it is you’re asking for. Are you looking for a way to specify an image origin? If I recall correctly, images are rendered based on an origin so if you transform them it is done around said origin. Or perhaps you’re looking for something else?July 12, 2019 at 10:39 am #16254
imageSample.Handle = New Vec2f( 0.5 )
Handle is the position when the rotation and scaling is centered.
0,0 is the default top left corner
1,1 is the bottom right corner
0.5,0.5 is the center of the image
It’s simple – but only when you know how and why 🙂July 12, 2019 at 5:41 pm #16256
Setting the origin worked wonderfully for scaling, thank you. Could you tell a way to alter the image offsets so that the relative centered region remains centered? Let’s say the image is centered above spain and the player zooms in, is there a way to maintain that center over spain?July 13, 2019 at 5:01 am #16257
Handle( 4.35, 2.9 )July 13, 2019 at 6:53 am #16258
handle is supposed to be from 0 to 1 for it to be inside the image.. (0,0) being top left and (1,1) bottom right.
image size is 1285*587
spain is at (560,170)
so your handle should be (560/1285,170/587) i.e. (0.435,0.29)
EDIT: note that dividing an int by an int will give an int. So in your code you’ll have to cast one of them to float: (zoomSpot.x/float(myImage. Width), zoomSpot.y/float(myImage.Height))July 13, 2019 at 5:43 pm #16259
Setting the handle works great for just zooming into a point on the image. The issue I am having is that I am unsure of how to alter the offsets of multiple points on the map to maintain their relative positions on the map while increasing scale, without altering the handle besides the initial setting to mid handle. For examples sake, say the player has a unit in south america, a unit in scotland, and a unit in New Zealand, is there an algorithm to alter the positions of these units so that they maintain their relative positions in these countries and don’t end up in the ocean?July 14, 2019 at 8:21 am #16261
I’m not sure I get what you want but here is some code where you can move arond the map and zoom/unzoom spain only.
It uses matrix transfrom which is something used a lot for zoom/rotate/translate. When you move around the map, you don’t move the map but the “camera”(ie the transform) instead. I’ve added a method to canvas to get the transfrom as a “center the camera on this point”.
You can zoom/unzoom spain with the I and O keys.Monkey123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126Namespace MainWindow'Library Imports#Import "<std>"#Import "<mojo>"#Import "<mojox>"'Images#Import "sample.png"Using std..Using mojo..Using mojox..Global windowWidth:Int = 1285Global windowHeight:Int = 587Class MainWindow Extends WindowField ImageSample:Image = Image.Load("asset::sample.png")Field xOffset:Int=windowWidth/2 'now this is the camera center pointField yOffset:Int=windowHeight/2 'now this is the camera center point'Field selX:Int'Field selY:IntField zoom:Float = 0.5Field spainImage:ImageField spainOffset:Vec2iField spainZoom:=0.6Field debugOverlay:Bool = TrueMethod New()Super.New("Image Scaling",windowWidth,windowHeight,WindowFlags.Center)'copy pasting the spain portion to a small image (37*37 so the real center exists, trickyer for even size images)Local tempWorldCanvas:=New Canvas(ImageSample)Local spainPixmap:=tempWorldCanvas.CopyPixmap(New Recti(New Vec2i(537,152),New Vec2i(537+37,152+37)))spainImage=New Image(spainPixmap)spainImage.Handle=New Vec2f(0.5,0.5)spainOffset=New Vec2i(537+18,152+18) '18 is 37/2.0 tounded downEndMethod OnRender(canvas:Canvas) OverrideApp.RequestRender()'selX = (Mouse.X - xOffset)'selY = (Mouse.Y - yOffset)If Keyboard.KeyDown(Key.Z) Thenzoom -= 0.01'Increase offsetsxOffset += 0yOffset += 0EndifIf Keyboard.KeyDown(Key.X) Thenzoom += 0.01'Decrease offsetsxOffset -= 0yOffset -= 0EndifIf Keyboard.KeyDown(Key.W) Then yOffset += 3*(1/zoom)If Keyboard.KeyDown(Key.S) Then yOffset -= 3*(1/zoom)If Keyboard.KeyDown(Key.A) Then xOffset += 3*(1/zoom)If Keyboard.KeyDown(Key.D) Then xOffset -= 3*(1/zoom)If Keyboard.KeyDown(Key.I) Then spainZoom += 0.01If Keyboard.KeyDown(Key.O) Then spainZoom -= 0.01canvas.PushMatrix()'remeber state of the matrixcanvas.SetCameraByCenter(New Vec2f(xOffset,yOffset),zoom)canvas.Alpha = 1Local mouseOnMap:=-canvas.Matrix*MouseLocation 'use inverted matrix to get mouse location on the mapcanvas.DrawImage(ImageSample,0,0,0,1,1)If Keyboard.KeyHit(Key.R) Then debugOverlay = Not debugOverlayIf debugOverlay = True Thencanvas.Alpha = 0.5'canvas.DrawImage(ImageSample,xOffset,yOffset,0,zoom+0.01,zoom+0.01)canvas.DrawImage(spainImage,spainOffset.x,spainOffset.y,0,spainZoom,spainZoom)canvas.Alpha = 1Endifcanvas.PopMatrix() 'recover state of the matrix'Debug stuffcanvas.DrawRect(windowWidth/2,windowHeight/2,2,2)canvas.DrawText(xOffset+","+yOffset,0,0)canvas.DrawText(mouseOnMap,0,16)canvas.DrawText(zoom,0,48)If Keyboard.KeyHit(Key.Escape) Then App.Terminate()EndEndClass Canvas ExtensionMethod SetCameraByCenter(point:Vec2f,zoom:Float=1.0,rotation:Float=0.0)Translate(Viewport.Width/2.0,Viewport.Height/2.0)Scale(zoom,zoom)Rotate(rotation)Translate(-point)EndEndFunction Main()New AppInstanceNew MainWindowApp.Run()EndJuly 14, 2019 at 8:50 am #16262
You must be logged in to reply to this topic.