I've got an image that's allowed to be rotated and scaled by the user.
Every time the user clicks the image I try to figure out if the point is transparent or not.
If it's transparent I return null in my view's HitTest, if it's not transparent I return the view. Problems start when user rotates the image. In my hitTest method, I need to transform the point according to the current view's rotation. Otherwise the point will indicate an irrelevant location on the view (and the image).
How do I do that?
Thank you very much.
This CGAffineTransform Reference might help:
CGPointApplyAffineTransform
CGRectApplyAffineTransform
and
CGSizeApplyAffineTransform
But before you start thinking that you need to perform the mapping by hand, I would suggest to give it a try 'as if' the current transformation was CGAffineIdentity, and code your coordinate detection accordingly. You might be surprised by the results ...
My own experience says that it looks like when you get your points from UITouch locationIn_SomeView_ the inverted matrix of SomeView is applied to the point before it is handed back to you.
So, you probably don't need any of the CGxxxApplyAffineTransform unless you generate the points yourself, outside of the events system.
Related
i have the requirement to perform a redaction in itext7. We have several rectangles which have been selected by the user. Some of these have been rotated. I have not found the ability to rotate rectangles in itext7. Usually, how we draw "rotated" rectangles is to perform some mathematical operations on a "fake" rectangle we draw in the code, and then draw them either using a series of lines like so:
if (rect.mRotation > 0)
{
r.Rotate(DegreeToRadian(rect.mRotation));
}
c.MoveTo(r.TopLeft.X, r.TopLeft.Y);
c.LineTo(r.TopRight.X, r.TopRight.Y);
c.LineTo(r.BottomRight.X, r.BottomRight.Y);
c.LineTo(r.BottomLeft.X, r.BottomLeft.Y);
c.LineTo(r.TopLeft.X, r.TopLeft.Y);
c.Stroke();
In the case of images, or something similar, we are unable to do the above. In this case we use an affinetransform to simulate the movement, which is applied to the image before it is added to the document. Both of the previous methods work perfectly.
Unfortunately for us, the pdfSweep tool only accepts (iText.Kernel.Geom) rectangles. We are looking for a way to be able to still pass an iText.Kernel.Geom.Rectangle which has had transforms applied (ie. a rectangle which has been rotated). We have tried setting the llx/urx values manually using the setBBox method, but this wont affect the rotation.
Does anyone know how we can go about redacting items over a given rectangular area which has been rotated?
Thanks
I'm playing with OpenGL ES on iPhone and I'm trying to rotate a model by panning with the finger. I discovered the open source app Molecules that let's you do that and I'm looking at that code, but when it comes to rotate a model of mine I'm able to rotate it only around a point distant in the space (like it was in orbit as a satellite and I am the fixed planet).
Any suggestion on what can be wrong?
I can post the code later , maybe on demand (many lines)
For the most part refer to Molecules you can find it here MOLECULES
If my memory serves me correctly, I think you need to translate the model to the origin, rotate, and then translate back to starting position to get the effect you are after.
I think there is a glTranslate() function, Say the object is at 1,0,0. You should then translate by -1,0,0 to go to origin. That is translate by a vector going from the center of the object to the origin.
The draw code probably looks roughly like this:
glLoadIdentity();
glTranslate(0, 0, -10);
glRotate(...);
drawMolecule();
Now it's important to realize that these transformations are applied in reverse order. If, in drawMolecule, we specify a vertex, then this vertex will first be rotated about the axis given to glRotate (which by definition passes through the local origin of the molecule), and then be translated 10 units in the −z direction.
This makes sense, because glTranslate essentially means: "translate everything that comes after this". This includes the glRotate call itself, so the result of the rotation also gets translated. Had the calls been reversed, then the result of the translation would have been rotated, which results in a rotation about an axis that does not pass through the origin anymore.
Bottom line: to rotate an object about its local origin, put the glRotate call last.
I've hooked up a UITapGestureRecognizer to a UIImageView containing the image I'd like to display on an iPad screen and am able to consume the user taps just fine. However, my image is that of a hand on a table and I'd like to know if the user has tapped on the hand or on the table part of the image. I can get the x,y coordinates of the user tap with CGPoint tapLocation = [recognizer locationInView:self.view]; but I'm at a loss for how to map that CGPoint to, say, the region of the image that contains the hand vs. the region that contains the table. Everything I've read so far deals with determining if a CGPoint is in a particular rectangular area, but what if you need to determine if that CGPoint is located in the boundaries of a more irregular shape? Is that even possible? Any suggestions or just pointing me in the right direction would be a big help. Thanks!
You could use pointInside:withEvent: to define the hit area programmatically.
To elaborate, you just take the point and evaluate to see if it falls in the area you're after with a series of if statements. If it does, return TRUE. If it doesn't, return FALSE. If this is related to this post, then you could use a circular conditional to compare the distance of the point to the center of your circle using Pythagorean Theorem.
late to the party,
but the core tool you want here is a "point in polygon" routine.
this is a generic approach, independent of iOS.
google has lots of info,
but the general approach is:
1) define your closed polygon.
- it sounds like this might be a bit of work in your case.
2) choose any point not equal to your original point.
(yes, any point)
3) for each edge in the polygon,
determine if the ray from your original point through the seconds point intersects with that polygon edge.
- this requires a line-segment-intersect-ray routine, also available on the 'tubes.
4) if the number of intersections is odd, it's inside the polygon.
if the count is even, it's outside.
for general geometry-type issues,
i highly recommend Paul Bourke: http://local.wasp.uwa.edu.au/~pbourke/geometry/insidepoly/
You can use a bounding rectangle that covers most or all of the hand.
If the user is using his finger to tap either the hand or the table, I doubt that you want him or her to be extremely precise with the tap.
An extension of the bounding rectangle answer,
you could define several smaller bounding rectangles that would approximate a hand without covering the rest of the screen.
OR
you could use a list of rectangles, for each of your objects and put the hand at the end of the list. In this case, if you had a tap on button X on the top right hand of the screen which is technically inside the hand rectangle, it would choose the button X because that rectangle is found first.
define the shape by a black and white bitmap (1 bit per pixel). Check if the particular bit is set. This would eat a lot of memory if you had a lot of large shapes, but for one bitmap with a hand, it should not be a big deal.
define the shape as a polygon. Then you need to do point-in-polygon test. Wikipedia has a wonderful article on this, with links to code here: http://en.wikipedia.org/wiki/Point_in_polygon
iPad libraries might have this already implemented. Sorry, I cannot help you there, not an iPad developer.
I'm trying to implement "hand draw tool".
At the moment algorythm looks like that (I don't insert any code because methods are quite big, will try to explain an idea):
Drawing
In touchesStarted: method I create NSMutableArray *pointsArray and add point into it. Call setNeedsDisplay: method.
In touchesMoved: method I calculate points between last added point from the pointsArray and current point. Add all points to the pointsArray. Call setNeedsDisplay: method.
In touchesFinished: event I calculate points between last added point from the array and current point. Set flag touchesWereFinished. Call setNeedsDisplay:.
Render:
drawRect: method checks is pointsArray != nil and is there any data in it. If there is - it starts to traw circles in each point of this array. If flag touchesWereFinished is set - save current context to the UIImage, release pointsArray, set it to nil and reset the flag.
There are a lot disadvantages of this method:
It is slow
It becomes extremely slow when user touches and move finger for long time. Array becomes enormous
"Lines" composed by circles are ugly
I would like to change my algorithm to make it bit faster and line smoother.
In result I would like to have lines like on the picture at following URL (sorry, not enough reputation to insert an image): http://2.bp.blogspot.com/_r5VzEAUYXJ4/SrOYp8tJCPI/AAAAAAAAAMw/ZwDKXiHlhV0/s320/SketchBook+Mobile(4).png
Can you advice me, ho I can draw lines this way (smooth and slim on the edges)? I thought to draw circles with alpha gradient on the edges (to make lines smoother), but it will be extremely slowly IMHO.
Thanks for help
Update
I changed draw algorithm. Now every event I save UITouch and in the drawRect: method I draw path from prev. point to the current one. And dump UIImage from context every drawRect: invocation.
But I still have 2 questions:
Is it possible to draw more smooth. I mean if I draw quite fast, I easily can see that path path is a set of straight lines. But I want to draw curves, to make path smooth. Probably Bezier curves will help but I don't understand how they can help in this.
situation.
I want to start path with thiner line and finish with thiner line too. How I can do this line transform?
Thanks!
I am trying to figure out how can you drag an image while constraining its movement along a certain path.
I tried several tricks including animation along a path, but couldn't get the animation to play and pause and play backwards - so that seems out of the question.
Any ideas ? anyone ?
What you're basically trying to do is match finger movement to a 'translation' transition.
As the user touches down and starts to move their finger you want to use the current touch point value to create a translation transform which you apply to your UIImageView. Here's how you would do it:
On touch down, save the imageview's starting x,y position.
On move, calculate the delta from old point to new one. This is where you can clamp the values. So you can ignore, say, the y change and only use the x deltas. This means that the image will only move left to right. If you ignore the x and use y, then it only moves up and down.
Once you have the 'new' calculated/clamped x,y values, use it to create a new transform using CGAffineTransformMakeTranslation(x, y). Assign this transform to the UIImageView. The image moves to that place.
Once the finger lifts, figure out the delta from the original starting x,y, point and the lift-off point, then adjust the ImageView's bounds and reset the transform to CGAffineTransformIdentity. This doesn't move the object, but it sets it so subsequent accesses to the ImageView use the actual position and don't have to keep adjusting for transforms.
Moving along on a grid is easy too. Just round out the x,y values in step 2 so they're a multiple of the grid size (i.e. round out to every 10 pixel) before you pass it on to make the translation transform.
If you want to make it extra smooth, surround the code where you assign the transition with UIView animation blocks. Mess around with the easing and timing settings. The image should drag behind a bit but smoothly 'rubber-band' from one touch point to the next.
See this Sample Code : Move Me