After CGPointMake let me down I found out that we can initalise a static const CGPoint like this instead:
static const CGPoint p = { 0.f, 0.f };
It works but what is the curly bracket notation actually doing?
CGPoint is a struct:
struct CGPoint {
CGFloat x;
CGFloat y;
};
It's a valid method to initialize a struct in C. See Struct initialization of the C/C++ programming language?.
Related
Ok, so Im going straight off Apple's tutorial using a joystick moving an SCNNode for SceneKithere.
I've copied the code and gotten the joystick to both move and rotate the character - but not simultaneously, and not in the right direction relative to the node.
All the correct code is in that download, but what I've done is here is where I get the angle offset of the joystick handle and the float2 from the joystick UI-
characterDirection = float2(Float(padNode.stickPosition.x), -Float(padNode.stickPosition.y))
let direction = theDude.characterDirection(withPointOfView: renderer.pointOfView)
directionAngle = CGFloat(atan2f(direction.x, direction.z))
public func characterDirection(withPointOfView pointOfView: SCNNode?) -> float3 {
let controllerDir = theDude.direction //THIS ISNT BEING UPDATED
if controllerDir.allZero() {
return float3.zero
}
var directionWorld = float3.zero
if let pov = pointOfView {
let p1 = pov.presentation.simdConvertPosition(float3(controllerDir.x, 0.0, controllerDir.y), to: nil)
let p0 = pov.presentation.simdConvertPosition(float3.zero, to: nil)
directionWorld = p1 - p0
directionWorld.y = 0
if simd_any(directionWorld != float3.zero) {
let minControllerSpeedFactor = Float(0.2)
let maxControllerSpeedFactor = Float(1.0)
let speed = simd_length(controllerDir) * (maxControllerSpeedFactor - minControllerSpeedFactor) + minControllerSpeedFactor
directionWorld = speed * simd_normalize(directionWorld)
}
}
return directionWorld
}
I didn't write the last part and still trying to understand it. But what is relevant is I have a float3 and an angle, and they are conflicting when I try to run them both as SCNActions in my renderer update func:
Here is what Apple basically had in update:
// move
if !direction.allZero() {
theDude.characterVelocity = direction * Float(characterSpeed)
var runModifier = Float(1.0)
theDude.walkSpeed = CGFloat(runModifier * simd_length(direction))
// move character - IMPORTANT
theDude.directionAngle = CGFloat(atan2f(direction.x, direction.z))
theDude.node.runAction(SCNAction.move(by: SCNVector3(theDude.characterDirection(withPointOfView: theDude.node)), duration: TimeInterval(40))) //HERE - random time
theDude.isWalking = true
} else {
theDude.isWalking = false
theDude.node.removeAllActions()
}
}
Where on the commented line I applied the move and here Apple had the rotation applied:
var directionAngle: CGFloat = 0.0 {
didSet {
theDude.node.runAction(
SCNAction.rotateTo(x: 0.0, y: directionAngle, z: 0.0, duration: 0.1, usesShortestUnitArc:true))
}
}
They are both happening, problem is I don't know really what to put as my time and my node moves say, left when I have the joystick pointed right, etc because I am not doing the move correctly.
I tried to copy the demo but they have a moving floor, so it is different. What am I doing wrong here?
I have a a set of CGPoints which represent a shape which is a bit like an upside down 'T' shape, now I want to convert those points into a CGRect which fits inside the shape, so to create a CGRect which encompasses the entire shape I just loop through and work out the lowest x and y for the top left and the highest x and y for the bottom right which is great but leaves white areas outside of the image, how could I figure out the largest rectangle without white areas so the final shape is more like an '|' shape? My code so far:
CGPoint topLeft = CGPointZero;
CGPoint bottomRight = CGPointZero;
for( NSValue *value in points ) {
CGPoint point = [value CGPointValue];
if( topLeft.x == 0 || topLeft.x > point.x ) shapeRect.x = point.x;
if( topLeft.y == 0 || topLeft.y > point.y ) shapeRect.y = point.y;
if( bottomRight.x < point.x ) bottomRight.x = point.x;
if( bottomRight.y < point.y ) bottomRight.y = point.y;
}
CGRect shapeRect = CGRectMake(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, bottomRight.y - topLeft.y);
EDIT: I've drawn some pics to show what I'm trying to achieve. Grey areas show the CGRect.
Here's the image shape, I have coordinates for each point in the shape:
Image Hosted by ImageShack.us http://img684.imageshack.us/img684/121/crop1.png
Here's what my code above produces:
Image Hosted by ImageShack.us http://img26.imageshack.us/img26/2521/crop2j.png
Here's what I'm trying to achieve:
Image Hosted by ImageShack.us http://img689.imageshack.us/img689/5499/crop3.png
Hard to get a grip on what you are actually asking about. In regards to the title this function will create the smallest rect for any number of CGPoints.
CGRect CGRectSmallestWithCGPoints(CGPoint pointsArray[], int numberOfPoints)
{
CGFloat greatestXValue = pointsArray[0].x;
CGFloat greatestYValue = pointsArray[0].y;
CGFloat smallestXValue = pointsArray[0].x;
CGFloat smallestYValue = pointsArray[0].y;
for(int i = 1; i < numberOfPoints; i++)
{
CGPoint point = pointsArray[i];
greatestXValue = MAX(greatestXValue, point.x);
greatestYValue = MAX(greatestYValue, point.y);
smallestXValue = MIN(smallestXValue, point.x);
smallestYValue = MIN(smallestYValue, point.y);
}
CGRect rect;
rect.origin = CGPointMake(smallestXValue, smallestYValue);
rect.size.width = greatestXValue - smallestXValue;
rect.size.height = greatestYValue - smallestYValue;
return rect;
}
Can be used like this
CGPoint poinstArray[] = {topLeft, bottomRight};
CGRect smallestRect = CGRectSmallestWithCGPoints(poinstArray, 2);
Swift version of hfossli (it works great !) :
func pointToRect(pointsArray: [CGPoint]) -> CGRect {
var greatestXValue = pointsArray[0].x
var greatestYValue = pointsArray[0].y
var smallestXValue = pointsArray[0].x
var smallestYValue = pointsArray[0].y
for point in pointsArray {
greatestXValue = max(greatestXValue, point.x);
greatestYValue = max(greatestYValue, point.y);
smallestXValue = min(smallestXValue, point.x);
smallestYValue = min(smallestYValue, point.y);
}
let origin = CGPoint(x: smallestXValue, y: smallestYValue)
let size = CGSize(width: greatestXValue - smallestXValue, height: greatestYValue - smallestYValue)
return CGRect(origin: origin, size: size)
}
If I did not misunderstand the question, your aim is to find the blue points:
If I'm correct, then it's enough for you to store two points (say topL and topR) and a value (say bottom).
Iteratively:
check if the current point has y < topL.y and eventually update topL and topR.
If instead y == topL.y check if current x is less than topL.x. If yes update topL
otherwise check if current x>topR.x; if yes update topR.
check if current y>bottom. If yes update bottom.
Note that when I say "update topL" I mean both x and y.
At the end you can get your bottom-left and bottom-right points using x coordinate of topL and topR and setting y coordinate to bottom.
If you want, you can use Core Graphics:
let path = CGMutablePath()
path.addLines(between: [p1, p2, p3, p4])
return path.boundingBoxOfPath
Hopefully you're only talking about this one shape, always oriented this way, otherwise this becomes a tricky computational geometry problem (something like the largest enclosed rectangle in a concave polygon).
Given your list of points, the following should work:
a. Find the point with the largest y value.
b. Find the other point with an equally large y value.
c. Compare the x values of these two and determine which is leftmost.
Find the minimum y value of all the points.
Create two new points, each with an x value equal to one of the points you found in step 1, and with the y value found in step 2.
The two points from step 1 are your top left and right points, and the two created in step 3 are the bottom left and right. You can now construct the final rectangle.
I am designing a Padding struct as follows:
/* Padding. */
struct CGPadding {
CGFloat left;
CGFloat top;
CGFloat right;
CGFloat bottom;
};
typedef struct CGPadding CGPadding;
CG_INLINE CGPadding CGPaddingMake(CGFloat left, CGFloat top, CGFloat right, CGFloat bottom) { CGPadding p; p.left = left; p.top = top; p.right = right; p.bottom = bottom; return p; }
This all works perfectly well, the problem is how can I create a const CGPadding CGPaddingZero? If I do like this:
const CGPadding CGPaddingZero = (CGPadding){0.0, 0.0, 0.0, 0.0};
It doesnt work. So what am I doing wrong?
I find this very interesting because I do it all the time on the iPhone and it works fine. May it have something to do with the typedef afterward to the same name? What if you get rid of the typedef and define your struct like this?
typedef struct CGPadding {
CGFloat left;
CGFloat top;
CGFloat right;
CGFloat bottom;
} CGPadding;
Does it work then? Also, since all 0's is zero for a float as well and you're zero-ing out the whole thing, you could just say
const CGPadding CGPaddingZero = {0};
I do this stuff all the time on the iPhone so I'd be quite surprised if it doesn't work for you.
i have a struct HLRange with two CGFloat's
struct HOLRange
{
CGFloat min;
CGFloat max;
};
typedef struct HOLRange HOLRange;
but how do i make a function like HLRangeMake(1,2); .. like CGRectMake?
--EDIT--
my header file
#import <Foundation/Foundation.h>
struct HOLRange
{
CGFloat min;
CGFloat max;
};
typedef struct HOLRange HOLRange;
HOLRange HOLRangeMake(CGFloat min, CGFloat max) {
HOLRange range;
range.min = min;
range.max = max;
return range;
}
#interface Structs : NSObject {
}
#end
error message: ld: duplicate symbol _HOLRangeMake in /Users/Documents/projects/iphone/test/catalog/base1/build/base1.build/Debug-iphoneos/base1.build/Objects-normal/armv6/base1AppDelegate.o and /Users/Documents/projects/iphone/test/catalog/base1/build/base1.build/Debug-iphoneos/base1.build/Objects-normal/armv6/main.o
HOLRange HLRangeMake(CGFloat min, CGFloat max) {
HOLRange range;
range.min = min;
range.max = max;
return range;
}
You can see CGRectMake source in CGGeometry.h so you can do the same:
CG_INLINE CGRect
CGRectMake(CGFloat x, CGFloat y, CGFloat width, CGFloat height)
{
CGRect rect;
rect.origin.x = x; rect.origin.y = y;
rect.size.width = width; rect.size.height = height;
return rect;
}
Edit: You must either define your function as inline or move its implementation to .m file. You're getting linker errors as you function becomes defined in every compile unit that imports HoleRange.h (?) header.
Old post. However, I'd like to share my method of resolving this problem for future viewers.
typdef struct _HOLRange {
CGFloat min;
CGFloat max;
} HOLRange;
static inline HOLRange(CGFloat min, CGFloat max) {
return (HOLRange) {min, max};
}
You can define your stuct and Make function like this. Short and quick.
I like the format of this better. It makes more sense visually and seems more "correct."
typedef struct {
CGFloat min;
CGFloat max;
} HOLRange;
static inline HOLRange HOLRangeMake(CGFloat min, CGFloat max) {
HOLRange range;
range.min = min;
range.max = max;
return range;
}
I'd like to create a simple object that I can access like this:
myobject.floatValue1 = 1.0;
myobject.floatValue2 = 2.0;
It shouldn't have anymore than the two properties. Is it possible to create an enum or typedef with such a simple structure. Or must I create a class?
Sure, just make a C structure:
struct myStruct
{
float floatValue1;
float floatValue2;
};
typedef struct myStruct myType;
Then use it like this:
myType myVariable = {0.0, 0.0}; // optional initialization
myVariable.floatValue1 = 1.0;
myVariable.floatValue2 = 2.0;
Take a look at using a struct, e.g.:
struct MyObjectType {
float floatValue1;
float floatValue2;
};
...
MyObjectType myobject;
myobject.floatValue1 = 1.0;
myobject.floatValue2 = 2.0;