I'm having problems with this method. I have two rectangles that are obviously contained within each other.(I've even graphed their coordinates manually to make sure.) When I use CGRectContainsRect to compare these two rectangles, it returns false. For the life of me, I have tried everything, scoured the net, and I can't find an answer to this problem. Anyone have any idea why? I've included the values for the CGRects when I debug to show that they are definitely within each other.
-(bool)checkBoundingBox {
bool returnItem = YES;
//Checks for sprite interaction
for (int i = 0; i < [arrGameItems count]; i++) {
CGRect rect2 = [[self getChildByTag:1] boundingBox];
CGRect rect1 = [[self getChildByTag:3] boundingBox];
// rect1 = CGRectStandardize(rect1);
// rect2 = CGRectStandardize(rect2);
if (CGRectContainsRect(rect2, rect1)) {
CCLOG(#"removed child b*&ch");
[self removeChildByTag:[arrGameItems count] cleanup:YES];
returnItem = NO;
}
}
CCLOG(#"g-dammit");
return returnItem;
}
rect1
origin x = 141 y = 76, height = 25, width = 25
rect2
origin x = 127 y = 91, height = 25, width = 25
CGRectContainsRect() checks if one rectangle completely encompasses another, not just if they intersect. From your coordinates, the rectangles don't contain each other, but just intersect. You're looking for CGRectIntersectsRect().
rect1 does not contain rect2 in your example.
Rect 1 x coordinates span from 141 to 166.
Rect 2 x coordinates span from 127 to 152.
Therefor, rect2 is not contained within rect1 (because rect2 exists within x coordinates 127-140, and rect1 does not exist in those coordinates).
Related
I want to create a grid of rectangles at the centre of screen leaving some space on the edges. The need of that arises because I am spewing different sprites at random points and they keep spawning on top of eat other. So i thought if there is a way of creating a class that creates the grid and returns me with a random rect and mark it occupied as long at the sprite stays in that rect and make it free after.
If i can get some help or any tips it will be great. Any other solutions to achieve this are welcome too.
Thanks.
You could nest two for loops, one for rows and one for columns, make them both run 5 times, and in each loop increment the x position and y position by one-fifth the width and height of the screen and put these coordinates into a CGRrect. That would do what you want.
Thanks #andrewx for your help. This will create CGRect in the given range and then return a random one.
-(void) makeCGRectArray{
rectsArray = [[NSMutableArray alloc] init];
for (int x = 30; x<=420; x= x+60) {
for (int y=40; y<=280; y=y+40) {
CGRect newRect = CGRectMake(x, y, 60, 40);
[rectsArray addObject:[NSValue valueWithCGRect:newRect]];
}
}
[self getRandomCgrect:rectsArray];
}
-(CGRect) getRandomCgrect:(NSMutableArray*) rectArray{
NSInteger randomPoint = (arc4random() % (49));
CGRect randomRect = [[rectsArray objectAtIndex:randomPoint] CGRectValue];
self.isOccupied = YES;
return randomRect;
}
I am working in a project where the images are drag able. In which if i put one image over the other image the image has to be changed.
What i need is
1) I want to check whether both the images are in same place or not.
2) The position of image must not be exact.It may be approximately equal
If you want to check if two UIImages intersect, this is a good way:
CGRect rect1 = myView1.frame;
CGrect rect2 = myView2.frame;
if (CGRectIsNull(CGRectIntersection(rect1, rect2))) {
//They collide
}
You have all the info you need about this here:
https://developer.apple.com/library/mac/#documentation/graphicsimaging/reference/CGGeometry/Reference/reference.html
//for checking whether one image is inside another image
if(CGRectContainsRect(ImageView1.frame, ImageView2.frame))
{
//your code for overlapping here
}
//for checking whether one image intersects another
if(CGRectIntersectsRect(ImageView1.frame,ImageView2.frame))
{
//your code for intersection here
}
Here is an approach assuming the images are the same size
// using ints because it is easier for taking the abs value
int dx,dy;
dx = frame1.origin.x - frame2.origin.x;
dy = frame1.origin.y - frame2.origin.y;
dx = abs(dx);
dy = abs(dy);
// overlapping width and height
int ovHeight, ovWidth;
ovWidth = frame1.size.width-dx;
ovHeight = frame1.size.height-dy;
int ovArea = ovWidth*ovHeight;
int imageArea = frame1.width*frame1.height;
int percentOverlap = ovArea*100/imageArea;
if (percentOverlap > 80) {
// do work here
}
CGRect frame1 = imgView1.frame;
CGRect frame2 = imgView2.frame;
this will give you two frame structures..which consist of origin(x,y) values and size(width,height) values..
compare according to your needs.
I'm using CorePlot to draw PieChart. I would like to display labels for slices on slices themselves. Is there a way to get coordinates of each slice and then setting the frame of CPTLayer that holds the text label to adjust to coordinates of the slice?
What I am doing so far:
-(CPRLayer*) datLabelForPlot(CPTPlot*)plot recordIndex:(NSUInteger)index {
static CPTMutableTextStyle *textStyle = nil;
NSString *string = #"Test";
if ( !textStyle) {
textStyle= [[CPTMutableTextStyle alloc] init];
textStyle.color = [CPTColor whiteColor];
}
CPTLayer *layer = [[[CPTLayer alloc] initWithFrame:CGRectMake(50,50, 100, 20)]autorelease];
CPTTextLayer *newLayer = nil;
newLayer = [[[CPTTextLayer alloc] initWithText:string style:textStyle] autorelease];
[layer addSublayer:newLayer];
return layer;
}
but regardless of the layer frame, label is always displayed at the same position (outside the chart). How to set the appropriate layer frame to display the text on the slice itself?
Here is the image of the points I would like to know:
Have you tried setting the CPPieChart labelOffset property to a negative value? May be it doesn't provide the level of precision that you need, but it's an easy solution.
Positive Offset:
Negative Offset:
The centerAnchor is expressed as a fraction of the size of the plot area, so you can use the following code to compute its pixel position (point "O" on your picture):
CPTPieChart *pieChart; // the pie chart
CGRect plotAreaBounds = pieChart.plotArea.bounds;
CGPoint anchor = pieChart.centerAnchor;
CGPoint centerPoint = CGPointMake(plotAreaBounds.origin.x + plotAreaBounds.size.width * anchor.x,
plotAreaBounds.origin.y + plotAreaBounds.size.height * anchor.y);
You can look at the Core Plot source code to see how the pie chart computes the positions of the labels. This code accounts for slices that are "exploded" and centers the label between what you called points "A" and "B", offset by the labelOffset. It hides the label if the datasource returned a missing value (NAN) for the slice. The index corresponds to the datasource index of the pie slice. The relevant bits are:
double currentWidth = [self cachedDoubleForField:CPTPieChartFieldSliceWidthNormalized recordIndex:index];
if ( isnan(currentWidth) ) {
contentLayer.hidden = YES;
}
else {
id<CPTPieChartDataSource> theDataSource = id<CPTPieChartDataSource>)self.dataSource;
BOOL dataSourceProvidesRadialOffsets = [theDataSource respondsToSelector:#selector(radialOffsetForPieChart:recordIndex:)];
CGFloat radialOffset = 0.0;
if ( dataSourceProvidesRadialOffsets ) {
radialOffset = [theDataSource radialOffsetForPieChart:self recordIndex:index];
}
CGFloat labelRadius = self.pieRadius + self.labelOffset + radialOffset;
double startingWidth = 0.0;
if ( index > 0 ) {
startingWidth = [self cachedDoubleForField:CPTPieChartFieldSliceWidthSum recordIndex:index - 1];
}
CGFloat labelAngle = [self radiansForPieSliceValue:startingWidth + currentWidth / (CGFloat)2.0];
label.displacement = CGPointMake( labelRadius * cos(labelAngle), labelRadius * sin(labelAngle) );
contentLayer.hidden = NO;
}
I have a nib with a 2 UIViews and 2 UILabels with IBOutlet's in my controller.
I am increasing and decreasing the height of these UIViews to look like a bar to indicate when something is 100% or less - like a bar chart almost.
I am using the following method for both bars (reuse) however the first UIView (bar) positions correctly but the second is too low down - the Y axis is wrong. However the height of both is correct.
Anyone have any ideas? I have positioned them in interface builder already all I am actually doing in this method is changing the height (basically)
//Position the point, size and label of a rating bar
- (void)configureRatingBar:(UIView *)vRatingBar
andRatingLabel:(UILabel *)lRatingLabel
usingRating:(NSDecimalNumber *)rating
{
//NSDecimalNumber *foodRating = [self calculateRating:self.currentHotel.foodAndBeverageRating];
NSString *formattedRating = [self formatRating:rating];
lRatingLabel.text = formattedRating;
float newHeight = [rating floatValue]; //The height will be based on the rating 100 max
CGRect currentFrame = vRatingBar.frame; //Current frame of the rating view
//CGPoint currentPoint =
// [vRatingBar convertPoint:vRatingBar.frame.origin toView:vReviews];
CGPoint currentPoint = vRatingBar.frame.origin; //Current point of the rating view
float newYaxis = currentPoint.x + (100 - newHeight); //Y axis must move down with the decreasing rating from 0 (100 %) down
[vRatingBar setFrame:CGRectMake(currentPoint.x, newYaxis, currentFrame.size.width, newHeight)];
[lRatingLabel setFrame:CGRectMake(currentFrame.size.width / 34, newHeight - 20, 34, 21)];
}
I see you have this line:
float newYaxis = currentPoint.x + (100 - newHeight); //Y axis must move down with the decreasing rating from 0 (100 %) down
Where you are using currentPoint.x for the calculation. Should this be currentPoint.y?
I am struggling to get my custom drawing code to render at the proper scale for all iOS devices, i.e., older iPhones, those with retina displays and the iPad.
I have a subclass of UIView that has a custom class that displays a vector graphic. It has a scale property that I can set. I do the scaling in initWithCoder when the UIView loads and I first instantiate the vector graphic. This UIView is shown when the user taps a button on the home screen.
At first I tried this:
screenScaleFactor = 1.0;
if ([UIScreen instancesRespondToSelector:#selector(scale)]) {
screenScaleFactor = [[UIScreen mainScreen] scale];
}
// and then I multiply stuff by screenScale
... which worked for going between normal iPhones and retina iPhones, but chokes on the iPad. As I said, you can get to the UIView at issue by tapping a button on the home screen. When run on the iPad, if you display the UIView when at 1X, it works, but at 2X I get a vector graphic that twice as big as it should be.
So I tried this instead:
UPDATE: This block is the one that's right. (with the corrected spelling, of course!)
screenScaleFactor = 1.0;
if ([self respondsToSelector:#selector(contentScaleFactor)]) { //EDIT: corrected misspellng.
screenScaleFactor = (float)self.contentScaleFactor;
}
// again multiplying stuff by screenScale
Which works at both 1X and 2X on the iPad and on the older iPhones, but on a retina display, the vector graphic is half the size it should be.
In the first case, I query the UIScreen for its scale property and in the second case, I'm asking the parent view of the vector graphic for its contentsScaleFactor. Neither of these seem to get me where I want for all cases.
Any suggestions?
UPDATE:
Here's the method in my subclassed UIView (it's called a GaugeView):
- (void)drawRect:(CGRect)rect {
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSaveGState(context);
CGAffineTransform t0 = CGContextGetCTM(context);
t0 = CGAffineTransformInvert(t0);
CGContextConcatCTM(context, t0);
[needle updateBox];
[needle draw: context];
}
needle is of class VectorSprite which is a subclass of Sprite which is subclassed from NSObject. These are from a programming book I'm working through. needle has the scale property that I set.
updateBox comes from Sprite and looks like this:
- (void) updateBox {
CGFloat w = width*scale;
CGFloat h = height*scale;
CGFloat w2 = w*0.5;
CGFloat h2 = h*0.5;
CGPoint origin = box.origin;
CGSize bsize = box.size;
CGFloat left = -kScreenHeight*0.5;
CGFloat right = -left;
CGFloat top = kScreenWidth*0.5;
CGFloat bottom = -top;
offScreen = NO;
if (wrap) {
if ((x+w2) < left) x = right + w2;
else if ((x-w2) > right) x = left - w2;
else if ((y+h2) < bottom) y = top + h2;
else if ((y-h2) > top) y = bottom - h2;
}
else {
offScreen =
((x+w2) < left) ||
((x-w2) > right) ||
((y+h2) < bottom) ||
((y-h2) > top);
}
origin.x = x-w2*scale;
origin.y = y-h2*scale;
bsize.width = w;
bsize.height = h;
box.origin = origin;
box.size = bsize;
}
Sprite also has the draw and drawBody methods which are:
- (void) draw: (CGContextRef) context {
CGContextSaveGState(context);
// Position the sprite
CGAffineTransform t = CGAffineTransformIdentity;
t = CGAffineTransformTranslate(t,x,y);
t = CGAffineTransformRotate(t,rotation);
t = CGAffineTransformScale(t,scale,scale);
CGContextConcatCTM(context, t);
// draw sprite body
[self drawBody: context];
CGContextRestoreGState(context);
}
- (void) drawBody: (CGContextRef) context {
// Draw your sprite here, centered
// on (x,y)
// As an example, we draw a filled white circle
if (alpha < 0.05) return;
CGContextBeginPath(context);
CGContextSetRGBFillColor(context, r,g,b,alpha);
CGContextAddEllipseInRect(context, CGRectMake(-width/2,-height/2,width,height));
CGContextClosePath(context);
CGContextDrawPath(context,kCGPathFill);
}
How, exactly, are you rendering the graphic?
This should be handled automatically in drawRect: (the context you get should be already 2x). This should also be handled automatically with UIGraphicsBeginImageContextWithOptions(size,NO,0); if available (if you need to fall back to UIGraphicsBeginImageContext(), assume a scale of 1). You shouldn't need to worry about it unless you're drawing the bitmap yourself somehow.
You could try something like self.contentScaleFactor = [[UIScreen mainScreen] scale], with appropriate checks first (this might mean if you display it in an iPad at 2x, you'll get high-res graphics).
Fundamentally, there's not much difference between an iPad in 2x mode and a "retina display", except that the iPad can switch between 1x and 2x.
Finally, there's a typo: #selector(contentsScaleFactor) has an extra s.