This is kind of a mistake, although I'm not sure how serious. As you learned from your test, the contains() method does not work when transforms (translation / rotation / scale) are used.
I have several hacker workarounds:
- Saving a separate array of vertices, adding manually (offset / translation) and multiplying (scaling) position values, and then testing if the point is inside the polygon .
- Using the transformation matrix and the inverse transformation from the screen (typical processing) of coordinates to converted SVG coordinates.
The first solution sounds like little work and pointless duplication of data, not to mention annoyance when it comes to cornering, as well as errors prone to “complex” / complex transformations.
The second workaround looks a bit hacky, since contains () should just work, but it uses the use of processing classes, so it's not so bad. It works as follows:
- create a transformation matrix to which you apply the necessary transformation in your form (e.g. translate (), rotate (), scale ()) and save it
- apply this transformation to the form
- save the inverse transformation matrix to convert screen coordinates to svg coordinates (with transforms), and this method contains () will work.
svg comes from Examples> General> Form> GetChild . You can open the sketch folder (Ctrl + K / CMD + K) to get "usa-wikipedia.svg" if you want to test the code as is:
import processing.opengl.*; PShape ohio; PMatrix2D coordSysSvgInv;//svg coordinate system inversed void setup() { size(1200, 480,OPENGL);//the catch is, even though we use PMatrix2D, PShape applyMatrix() only seems to work with the P3D or OpenGL renderer PShape usa = loadShape("usa-wikipedia.svg"); ohio = (PShape)usa.getChild("OH"); PMatrix2D transform = new PMatrix2D(); //apply transforms(position,rotation,scale) to this matrix transform.scale(2); //be aware that the order of operation matters! transform.translate(-800,-300); //this matrix can be used to convert from screen coordinats to SVG coordinates coordSysSvgInv = transform.get(); //clone the svg to screen transformation matrix coordSysSvgInv.invert(); //simply invert it to get the screen to svg ohio.applyMatrix(transform); //apply this transformation matrix to the SVG } void draw() { //update PVector mouseInSVG = screenToSVG(mouseX,mouseY); boolean isOver = ohio.contains(mouseInSVG.x,mouseInSVG.y); //draw background(255); ohio.disableStyle(); fill(isOver ? color(0,192,0) : color(255,127,0)); shape(ohio); } PVector screenToSVG(float x,float y){ PVector result = new PVector();//create a new PVector to store transformed vector coordSysSvgInv.mult(new PVector(x,y),result);//transform PVector by multiplying it to the inverse svg coord. sys. return result; }
I noticed that the applyMatrix () method only works with P3D and OPENGL , I even thought that I was passing an instance of PMatrix2D , otherwise this warning appears:
applyMatrix() with x, y, and z coordinates can only be used with a renderer that supports 3D, such as P3D or OPENGL. Use a version without a z-coordinate instead.
The 'cleaner' option should change the contains () method in the PShape class, and then recompile Process core.jar and use the updated jar. If this is for a one-time small project, I don’t know whether it is worth worrying about, but it can faster have a bit more dirty code on top than recompiling / updating core.jar.