I have a UITextView which contains text and images. I also have a CGPoint array containing coordinates of images added by a user in the UITextFied. Whenever texts in the UITextView changes (addition or deletion), I get the position of the cursor which is a CGPoint object.
Now I want to loop through my CGPoint array to find how many images fall after the cursor position whether on the same line or lines below. How do I go about it?
Any help would be very much appreciated.
Sure:
var cursor = message.caretRectForPosition(message.selectedTextRange?.end).origin;
for i in 0...emoji1.count-1 {
if ((cursor.x > emoji_pt[i].x) && (cursor.y <= emoji_pt[i].y)) {
continue;
}
else {
//the emoji is after the cursor.
// Return the index and process all images after that index
}
}
To handle the Y position
Bool onPreviousLine = (emoji_pt[i].y < cursor.y)
To handle the X position (lineHeight being a constant depending on your case and the size of images, you could probably get away with some low constant value (e.g. 1.0)).
Bool onTheSameLine = abs(Double(emoji_pt[i].y - cursor.y)) < Double(lineHeight / 2)
Bool beforeX = (emoji_pt[i].x < cursor.x)
Together
if onPreviousLine || (onTheSameLine && beforeX) {
continue
}
Related
Currently I am plotting the graph with two data plots(two lines on the graph), when I click on one line "indexOfVisiblePointClosestToPlotAreaPoint" method giving me right index and other one throwing me wrong one, not even closest visible one its skipping/jumping multiple points in between. Ex: if I click on index number 20 it jumps to 15 or 25 vice versa. Here is the calculation to find the index
-(NSUInteger)indexOfVisiblePointClosestToPlotAreaPoint:(CGPoint)viewPoint
{
NSUInteger dataCount = self.cachedDataCount;
CGPoint *viewPoints = calloc(dataCount, sizeof(CGPoint));
BOOL *drawPointFlags = calloc(dataCount, sizeof(BOOL));
[self calculatePointsToDraw:drawPointFlags forPlotSpace:(CPTXYPlotSpace *)self.plotSpace includeVisiblePointsOnly:YES numberOfPoints:dataCount];
[self calculateViewPoints:viewPoints withDrawPointFlags:drawPointFlags numberOfPoints:dataCount];
NSInteger result = [self extremeDrawnPointIndexForFlags:drawPointFlags numberOfPoints:dataCount extremeNumIsLowerBound:YES];
if ( result != NSNotFound ) {
CGFloat minimumDistanceSquared = CPTNAN;
for ( NSUInteger i = (NSUInteger)result; i < dataCount; ++i ) {
if ( drawPointFlags[i] ) {
CGFloat distanceSquared = squareOfDistanceBetweenPoints(viewPoint, viewPoints[i]);
if ( isnan(minimumDistanceSquared) || (distanceSquared < minimumDistanceSquared)) {
minimumDistanceSquared = distanceSquared;
result = (NSInteger)i;
}
}
}
}
free(viewPoints);
free(drawPointFlags);
return (NSUInteger)result;
}
Are you checking the plot parameter passed in the delegate method? The touch will register on the frontmost plot if there are any points within the plotSymbolMarginForHitDetection. It won't even check the other plot unless nothing hits on the front one. With two lines close together like that, you'll need to use a small hit margin to make sure touches register on the right plot.
I'm using iOS charts framework to plot this chart, I want to detect tap or touch only on the line's path or on the small circle's on the lines.
My question is,
Is there any default code block to do this?
I tried comparing the entry.value with the array plotted(as in the following code), but it doesn't workout.
-(void)chartValueSelected:(ChartViewBase *)chartView entry:(ChartDataEntry *)entry dataSetIndex:(NSInteger)dataSetIndex highlight:(ChartHighlight *)highlight{
if ([arrayOfPlottedValues containsObject:[NSNumber numberWithInt:(int)entry.value]]) {
//Tapped on line path
}
else{
//Tapped on empty area
}
}
Any insights will be appreciated.
eg : Line chart
I found a way by considering #Wingzero's suggestion, but the major difference was that, I just used the touch point to find out if its on the "marker" or if its outside it. I'm not sure if its the right way, but the solution is,
-(void)chartValueSelected:(ChartViewBase *)chartView entry:(ChartDataEntry *)entry dataSetIndex:(NSInteger)dataSetIndex highlight:(ChartHighlight *)highlight{
//-----------------------------------------------------getting recognizer value
UIGestureRecognizer *recognisedGesture = [chartView.gestureRecognizers objectAtIndex:0];
CGPoint poinOfTouch =[recognisedGesture locationInView:chartView];
CGPoint poinOfMarker =[chartView getMarkerPositionWithEntry:entry highlight:highlight];
if (check if the chartview is BarChartView and if true) {
//-----------------------------------------------------If you want to detect touch/tap only on barchartview's bars
if (poinOfTouch.y > poinOfMarker.y) {
NSLog(#"within the bar area!");
}
else{
NSLog(#"Outside the bar area!");
}
}
else
{
//-----------------------------------------------------If you want to detect touch/tap only on linechartView's markers
//-----------------------------------------------------creating two arrays of x and y points(possible nearby points of touch location)
NSMutableArray *containingXValue = [[NSMutableArray alloc]init];
NSMutableArray *containingYValue = [[NSMutableArray alloc]init];
for (int i =0 ; i<5; i++) {
int roundedX = (poinOfMarker.x + 0.5);
int sumXValuesPositive = roundedX+i;
[containingXValue addObject:[NSNumber numberWithInt:sumXValuesPositive]];
int sumXValuesNegative = roundedX-i;
[containingXValue addObject:[NSNumber numberWithInt:sumXValuesNegative]];
int roundedY = (poinOfMarker.y + 0.5);
int sumYValuesPositive = roundedY+i;
[containingYValue addObject:[NSNumber numberWithInt:sumYValuesPositive]];
int sumYValuesNegative = roundedY-i;
[containingYValue addObject:[NSNumber numberWithInt:sumYValuesNegative]];
}
//-----------------------------------------------------------------------------------------------------------------------------------------
int roundXPointTOuched = (poinOf.x + 0.5);
int roundYPointTOuched = (poinOf.y + 0.5);
//-----------------------------------------------------check if touchpoint exists in the arrays of possible points
if ([containingXValue containsObject:[NSNumber numberWithInt:roundXPointTOuched]] && [containingYValue containsObject:[NSNumber numberWithInt:roundYPointTOuched]])
{
// continue, the click is on marker!!!!
}
else
{
// stop, the click is not on marker!!!!
}
//-----------------------------------------------------------------------------------------------------------------------------------------
}
}
}
Edit : The initial solution was applicable only for the line chart, Now if this same situation arises for bar chart, you could handle it with the above code itself.
Man, I'd been running around it for a while now, feeling really great for getting a positive lead. There is no direction for this issue yet, hope this will be useful for someone like me cheers!
P.S. I'm marking this as answer just to make sure, it reaches the needful :). Thanks
It has a default highlight logic, that is, calculate the closest dataSet and xIndex, so we know which data to highlight.
You can customize this logic to restrain the allowed smallest distance. e.g. define the max allowed distance is 10, if the touch point is away from the closest dot > 10, you return false and not highlgiht.
Highlighter is a class, like BarChartHighlighter, ChartHighlighter, etc.
Update towards your comment:
when you tapped, the delegate method get called, so you know which data is highlighted. Your codes seems fine, however the condition code is blackbox to me. But the delegate will be called for sure, so you only have to worry about your logic.
I'm using a SpriteKit game engine within XCode while developing a game that bounces a ball and platforms come from the sky and the objective is to bounce on the platforms to get higher. I need to add a velocity to the ball when it falls down + comes in contact with a platform. I'm having trouble trying to detect the balls Y position. I had something like this in the update method but nothing happens... I'm open to suggestions.
//The value of the _number instance variable is the Y position of the ball.
if (_number++) {
NSLog(#"UP");
}
if (_number--) {
NSLog(#"DOWN");
}
You can see a node's position by using code like this:
if(myNode.position.y > 0)
NSLog(#"y is greater than 0");
If you want to check a node's current speed (vector) you can do it like this:
if(myNode.physicsBody.velocity.dy > 0)
NSLog(#"Moving up");
if(myNode.physicsBody.velocity.dy < 0)
NSLog(#"Moving down");
Remember that position and speed (vector) are not the same thing.
You need to read the SKPhysicsBody docs to understand about CGVector and other important issues.
Alright, this:
if (_number++) {
NSLog(#"UP");
}
if (_number--) {
NSLog(#"DOWN");
}
doesn't work to do anything. It shouldn't even run. I don't why it doesn't give an error.
number++; is a simplified form of
number = number + 1;
You can't place it in an if statement.
First make the variable #property int ypos in your header.
Then every update compare the current y to the ypos.
After comparing, save the current y to ypos.
Place this in your Update method.
if (ball.position.y > _ypos)
{
//going up
}
else if (ball.position.y < _ypos)
{
//going down
}
_ypos = ball.position.y;
P.S. I haven't had access to a computer so the formatting might suck from my phone
When I use the 'UIPanGestureRecognizer' to move a 'UIImageView' object, I notice the 'center' attribute doesn't change. Why is this, am I doing something wrong? Here is the code:
func handlePanning1(recognizer: UIPanGestureRecognizer)
{
var index: Int = recognizer.view!.tag - 1 // index in the arrays for this piece
var newTranslation: CGPoint = recognizer.translationInView(pieces[index])
recognizer.view?.transform = CGAffineTransformMakeTranslation(lastTranslations[index].x + newTranslation.x, lastTranslations[index].y + newTranslation.y)
// THIS ALWAYS PRINTS OUT THE SAME WHILE I'M PANNING
// AND IF I PAN MULTIPLE TIMES IN DIFFERENT DIRECTIONS (AKA IT NEVER CHANGES)
print(Int(pieces[index].center.x))
print("\n")
if recognizer.state == UIGestureRecognizerState.Ended {
lastTranslations[index].x += newTranslation.x
lastTranslations[index].y += newTranslation.y
}
}
You are applying a transform to the view, you are not actually moving it. Think about it as though it is in a certain place but when it gets rendered, there are instructions to skew how it is show. If you want the view to have a different position, then you have to change its center property instead of transforming it.
I am drawing the line using following code, it works just amazing,
http://www.merowing.info/2012/04/drawing-smooth-lines-with-cocos2d-ios-inspired-by-paper/
Now I want to.....
1> Detect if the line Intersect with itself.
2) Detect if CCSprite is inside this closed line or not.
While searching I came across many logics for LineIntersection but none of them are accurate. I am giving one of them which detects an intersection, but it also detects it when there is no intersection of line.
First Method
- (BOOL) lineIntersectOccured:(CGPoint)t1 pointEnd:(CGPoint)t2
{
BOOL result = NO;
int pointsCount = [arrlinePoints count];
CGPoint cp1;
CGPoint cp2;
for(int i = 0, j = 1; j < pointsCount; i++,j++)
{
[[arrlinePoints objectAtIndex:i] getValue:&cp1];
[[arrlinePoints objectAtIndex:j] getValue:&cp2];
// lines connected do not need to be included.
if((cp2.x == t1.x && cp2.y == t1.y) || (cp1.x == t2.x && cp1.y == t2.y))
{
continue;
}
CGPoint diffLA = CGPointMake(cp2.x - cp1.x,cp2.y - cp1.y);
CGPoint diffLB = CGPointMake(t2.x - t1.x, t2.y - t1.y);
float compA = diffLA.x*cp1.y - diffLA.y * cp1.x;
float compB = diffLB.x*t1.y - diffLB.y*t1.x;
BOOL compA1 = (diffLA.x*t1.y - diffLA.y*t1.x) < compA;
BOOL compA2 = (diffLA.x*t2.y - diffLA.y*t2.x) < compA;
BOOL compB1 = (diffLB.x*cp1.y - diffLB.y*cp1.x) < compB;
BOOL compB2 = (diffLB.x*cp2.y - diffLB.y*cp2.x) < compB;
if(((!compA1 && compA2) || (compA1 && !compA2)) && ((!compB1 && compB2) || (compB1 && !compB2)))
{
result = YES;
}
}
return result;
}
And this is how I call this method,
I have stored my points in the arrLinePoints from pangesture recognizer method
if ([self lineIntersectOccured:[[arrlinePoints objectAtIndex:0] CGPointValue] pointEnd:[[arrlinePoints objectAtIndex:[arrlinePoints count] - 1] CGPointValue]] )
{
NSLog(#"Line Intersected");
}
This gives me true even with the Following Situation
I also have tried the same Functionality with different Approach by adding view into CCDirector's view
UIBezierPath intersect
But this is giving performance issues , my fps reduced to almost 3 to 6. And also that intersection issue remains the same.
The Perfect Situation for Intersection is
Please help as soon as possible!
Thanks for all Support.
As you construct the path yourself, it should not be necessary to test pixels. Instead use the points used to create the path.
It shouldn't be too hard to find a good line segment intersection algorithm. It seems the top answer of this question has a good method:
Determining if two line segments intersect?
Once you've found a hit, use that exact hit point and the history of points to construct a polygon.
From there you should be able to perform a "point in polygon" test.
A few tips for performance:
In search for the intersection, only check the newest line segment for collision with the others (all lines that did not intersect previously will not intersect with each other this time around)
You might skip segments when you can conclude that both points are on one extreme of the line segment, for example you could skip foreign if:
current.a.x < current.b.x && (foreign.a.x < current.a.x && foreign.b.x < current.a.x)
I hope this helps you along.
Not implemented though, I guess you can detect pixel value of the line drawn with the pixel value of your drawn line inside the touchesMoved method.
Or you can refer here for detailed approach. The same work has been done here.