Map an image to a polygon

Does anyone have a ready made snippet that will map a square image to a four sided polygon

In reality this is not a simple problem to solve.

About 15 years ago, I wrote code (in Xojo) that would divide the polygon by how many pixels I was intending to draw, then read the color from the picture and fill in a smaller polygon. It repeated this until the entire image had been drawn.

It was slow. I gave the code to Björn who converted into a format that he could include in a plugin. While this was much faster, it still wasn’t fast enough to provide a real-time preview (back in the day).

If you understand how to use NSTransforms or CGTransforms, it’s possible to use these to adjust a rectangle to fit within a four sided polygon. Without fully understanding the math behind it, it was a experience in frustration for me, but I was never that good at Math.

Alternatively Core Image has a filter for doing the above, all you need to do is to supply the four corners and it does the rest. As Core Image is GPU based, it can be fast enough to provide real-time previews on a modern Mac (especially when coupled with OpenGL or Metal), while OpenGL is deprecated I would still recommend it over Metal as there’s many little undocumented issues with CI+Metal.

At the moment CI+Metal is generating full page bright green graphics for me on BS, so there’s something broken or changed (again), I’d just about gotten a complete understanding of the quirks with CI+Metal on 10.14 & 10.15, and now I’m back to square one (again).

btw: It’s not just me who has issues with CI+Metal. I’ve had some discussions with developers of well known apps that use CI+Metal, and we’re all incredibly dissapointed in how much effort is required to keep these working in recent macOS versions (along with abysmal documentation).

TBH I’m not clear on what it is you need ?

given 3 square images… I need to map one into each of the colored shapes

each shaped is already defined by a Polygon Array (g.drawpolygon)

the Cyan and Orange are easy… its the magenta one I can’t figure

I can think of a brute force way but it has lots of assumptions like the area is consistently colored etc
Would that work ?

Like Sam mentioned, the easiest way would be to use affine transforms. I think the cyan and orange sides would be a skew transform while the purple side would be a rotate transform.

The easiest solution would be to use the graphic APIs built into the OS as these will also perform interpolation to produce a better result.

examples would be awesome

and it doesn’t need to be “real” time… I just need to make a series of static images

Dave, I would like to try to think about your problem, but I still don’t urdestand what you want to get from the image (most probably because of my english) . Would you mind explaining it in some other way?

Maybe you could say what you would get in that particular example.

One question, are those the colors you will always have in your images?

Thanks,

Julen

the colors are for illustration only… to denote where exactly the 3 images need to be mapped to…

So given 3 PNG images … map one each to the areas of color in the diagram
the end result would be a “3D cube” with textured faces.

I could go to the trouble to do this with SpriteKit… but these are static images… once it is created, it will be saved into a disk file for later use

Ok, thanks for the explanation.

Your magenta square image needs to be rotated 45 º around the center point and then the vertical dimension needs to be scaled down by a factor 3^(1/2) (square root of 3). I am considering your cube is represented in an isometric projection.

To rotate each pixel you will need to get the new position of each pixel ( you can do the calculation for only a fourth of the pixels, one quadrant of the original image, and use symmetry to get the position of the rest):
new_x = old_x * cos 45 - old_y * sin 45
new_y = old_y * cos 45 + old_x * sin 45

To compress the vertical dimension you will need to adjust only y:
Compressed_y = new_y/sqrt(3)

In addition (or maybe better as a first step), if the diagonal of the original image is larger/smaller than the horizontal diagonal of the magenta square you will first need to rescale the original image to make both diagonals match.

I am guessing you have many of these images and that’s why you need this done in code, otherwise adapting the images using image processing software should be easy.

I realize you asked for a snippet in your first post, but I hope this helps somehow. Also, I haven’t ried any of this but the general idea is there, and it should work.

Julen

EDIT: As soon as I posted I realized of something worth mentioning. The rotation will be done around the (0,0) pixel, not around the center point as said above. It doesn’t really matter but you will have to correct for the negative new_x values by adding L/sqrt(2) to all new_x values, where L is the size of the square image (again, if I am not worng, because I am trying to do all the math and visualization in my head… :upside_down_face:)

1 Like

Howdy Julen !

oh duh me … I’m thinking about taking that cube and finding the polygon that encloses the side

taking an image an transforming it to fit those sides is affine transforms

the top one would be a rotation of 45 degrees or so
and another rotation away from the screen some 30 degrees or so
since they occur in a 3D space you can rotate about the X Y or Z axis

Hi Norman, and everyone else.

1 Like

Well, I played around with this today by writing some Xojo code that can transform pictures using a matrix and hit the same problem as Dave.

It seems that a rotate by itself is not good enough for the top and you will in fact need to perform a perspective transform which is much more difficult.

If you can integrate with a command line tool to it might be worthwhile looking at ImageMagick as it has a -distort perspective command.

In OpenGL, this is called texture mapping. Maybe search google for an open-source function of mapping a texture to a triangle?

You can concatenate transforms or apply multiple transforms. So now you’ve done the rotation, you could scale the vertical axis.

1 Like

Maybe my old RB2007 tutorial on doing perspective using a Backward Quadrilateral Transformation could be of some help? The math should still stick.

Video of it at work:

Source code: http://www.gorgeousapps.com/Tut10.zip

Article: http://www.gorgeousapps.com/Tut10Article.pdf

3 Likes

Yes. I’m already doing a multiply to perform a skew & translate.

For some reason I didn’t try adding a scale in the y direction but it would be easy to add.

This would be much easier to solve using something like OpenGL or WebGL (-:

1 Like

The sides (I mean the orange and blue sides) of that cube are not correct. The angle between the the square images and the horizontal direction seems to be 45 º in your case but it should be 30 º.