Converting an NSMutableArray to an Array of C Structs - iPhone - OpenGL ES - iphone

I have an OpenGL ES based app which parses in information from an xml file using NSXMLParser. As the vertice information comes in for each scene object in the file, I am saving it in an NSMutableArray as follows :
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)string {
if (floatArray) {
if (currentlyParsing == kVerticeInformation) {
if (currentParserTagType == kGeometry) {
//NSLog(#"Loaded Vertices %#", string);
NSArray * nums = [string componentsSeparatedByString:#" "];
culmunativeCount += [nums count];
//NSLog(#"Culm Count is %d", culmunativeCount);
[fullParseString appendString : string];
if (checkSumCount <= culmunativeCount) {
//NSLog(#"Full Parse String is %#", fullParseString);
NSArray * finishedArray = [fullParseString componentsSeparatedByString:#" "];
//NSLog(#"Finihsed ARray is %d", [finishedArray count]);
[finishedParsingArray addObjectsFromArray:finishedArray];
//NSLog(#" FINISHED PARSING = %d", [finishedParsingArray count]);
NSUInteger baseIndex;
for (baseIndex=0; baseIndex <[finishedParsingArray count]; baseIndex +=3) {
NSString * xPoint = [finishedParsingArray objectAtIndex:baseIndex];
NSDecimalNumber * errorCheckX = [NSDecimalNumber decimalNumberWithString:xPoint];
float x = [errorCheckX floatValue];
NSString * yPoint = [finishedParsingArray objectAtIndex:baseIndex +1];
NSDecimalNumber * errorCheckY = [NSDecimalNumber decimalNumberWithString:yPoint];
float y = [errorCheckY floatValue];
NSString * zPoint = [finishedParsingArray objectAtIndex:baseIndex+2];
NSDecimalNumber * errorCheckZ = [NSDecimalNumber decimalNumberWithString:zPoint];
float z = [errorCheckZ floatValue];
vertex3D = [[Vertex3D alloc]init];
vertex3D.value1 = x;
vertex3D.value2 = y;
vertex3D.value3 = z;
[verticesArray addObject:vertex3D];
//NSLog(#"Vertices stored are %f, %f, %f", x,y,z);
}
currentlyParsing = kNilSetting;
checkSumCount = 0;
[finishedParsingArray removeAllObjects];
//Set object to adds vertice array to verticesArray;
vertex3D = nil;
objectToAdd.Vertices = verticesArray;
[verticesArray removeAllObjects];
//[finishedArray release];
culmunativeCount = 0;
[fullParseString setString:#""];
}
}
}
}
Vertex3D is a custom class to store the x,y,z points :
#import <Foundation/Foundation.h>
#interface Vertex3D : NSObject
{
float value1;
float value2;
float value3;
}
#property (assign) float value1;
#property (assign) float value2;
#property (assign) float value3;
#end
What I am then doing is passing this array to a SceneObject class which is instantiated for every object in the file. The idea is then to use these SceneObject objects to feed the OpenGL ES engine. I am using glDrawElements as the xml file uses indices.
The problem is that I cannot pass an NSMutable array into the OpenGL ES calls (such as glVertexPointer).
From an example I have been following at http://www.everita.com/lightwave-collada-and-opengles-on-the-iphone, it looks like I need to structure the vertices data as follows in order to use indices :
const Vertex3D tigerBottomPositions[] = {
{0.176567, 0.143711, 0.264963},
{0.176567, 0.137939, 0.177312},
{0.198811, 0.135518, 0.179324},
…
};
This is where I get a bit confused - I think this is an array of C structs which contains 3 Vertex3D objects, each of which contains three floats.
Can anybody advise me on how I can convert my NSMutableArray into a C struct in the correct format for use with OpenGL ES ? I'd also appreciate help on how to setup this C struct in code as my C knowledge is not as strong as my obj c.
Thank you in advance !

You need a dynamic array... given a C structure Vertex3D (not an Objective-C class):
NSArray *arr = ...;
const size_t count = [arr count];
Vertex3D *positions = (Vertex3D*)calloc(count, sizeof(Vertex3D));
for (size_t i=0; i<count; ++i) {
positions[i].x = ...;
// ...
}
// ... use positions
free(positions); // clean up

Related

how to save the touched position of x and y values in a array

I'm working with the cocos2d 3.x and Xcode 5.1.1.i'm doing the game like a candy crush,here i load the sprites to 5*5 matrix,and i already get the position for the touched sprite,now i need to save and use that x,y value in a array like (0,0),(3,0),(2,2)
there are a few of ways to store coordinates, it is hard to tell which way would fit better for, regarding I don't know what you mean exactly when you say save...
options #1
CGPoint _coords = CGPointMake(x, y);
obvious choice to store them in a CGPoint struct, however the struct is designed to store fraction coordinates, but it can handle integer values as well.
you cannot insert a CGPoint directly into any collection type, like e.g. NSArray, NSSet or NSSDictionary, but you can store them in e.g. a fix-sized C-array, like:
CGPoint _fiveCoordinates[4];
option #2
NSString *_coordinates = [NSString stringWithFormat:#"%d %d", x, y];
that is a quick and ugly solution, I personally don't like it – however in certain cases is useful (vs. option #4!). it is also possible to store it any collection type, and you can extract the coordinates after, for further usage, like e.g.:
NSArray *_components = [_coordinates componentsSeparatedByString:#" "];
NSInteger x = [[_components firstObject] integerValue];
NSInteger y = [[_components lastObject] integerValue];
if you'd store the values in a simple NSArray like
NSArray *_coordinates = [NSArray arrayWithObjects:#(x), #(y)];
the extraction procedure would be the similar to the idea above.
option #3
NSDictionary *_coordinates = [NSDictionary dictionaryWithObjectsAndKeys:#(x), #"x", #(y), #"y"];
a simple dictionary can store them flawlessly, if you need to extract the values, it is like e.g.
NSInteger x = [[_coordinates valueForKey:#"x"] integerValue];
NSInteger y = [[_coordinates valueForKey:#"y"] integerValue];
option #4
NSIndexPath *_coordinates = [NSIndexPath indexPathForRow:y inSection:x];
if you like to work with index paths, that is a very straightforward way to store indices, because the NSIndexPath widely used and can be inserted directly into any collection type.
extracting the coordinates would be the same easy way:
NSInteger x = [_coordinates section];
NSInteger y = [_coordinates row];
option #5A
another obvious way would be that creating an own class to store those coordinates, like e.g.:
.h
#interface MyCoordinates : NSObject { }
#property (nonatomic) NSinteger x;
#property (nonatomic) NSinteger y;
#end
.m
#implementation MyCoordinates
#end
option #5B
and you can also extend it comforming the NSCoding protocol, if you want to get a pure serialisable object, which can be archived with the NSArray for permanent storing, like:
.h
#interface MyCoordinates : NSObject <NSCoding> { }
#property (nonatmic) NSInteger x;
#property (nonatmic) NSInteger y;
#end
.m
#implementation MyCoordinates
#pragma mark - <NSCoding>
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super init]) {
_x = [[aDecoder decodeObjectForKey:#"x"] integerValue];
_y = [[aDecoder decodeObjectForKey:#"y"] IntegerValue];
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)aCoder {
[aCoder encodeObject:#(_x) forKey:#"x"];
[aCoder encodeObject:#(_y) forKey:#"y"];
}
#end
...or something similar, or you can combine them together as you'd feel which the most convenient way is in your personal view.
//SET
NSMutableArray* points = [[NSMutableArray alloc] initWithCapacity:10];
CGPoint pointToBeStored = CGPointMake(0,0);
[points addObject:[NSValue valueWithCGPoint:pointToBeStored]];
//GET
NSValue *value = [points objectAtIndex:index];
CGPoint storedPoint = [value CGPointValue];

Sharing Struct Information Between Classes - Objective C - OpenGL ES

I have an OpenGL ES based app with the following structure :
I parse vertices from a DAE file which contains a number of objects (using NSXMLParser).
As I parse each set of vertices, I create an object (sceneObject) and set the vertices array in this object to match the parsed vertices. I am then planning to add these sceneObjects to array of objects to be rendered by OpenGL ES.
Initially I had taken an approach of using NSArrays to store the vertice data, however I understand that the OpenGL commands (such as glvertexpointer) do not accept NSObject values, bue instead need raw values (glfloats and gluints etc).
Rather than convert the NSObjects back to GL raw values within the object class, I am now trying to take a struct approach. This is the code where I parse the vertice information :
if (floatArray) {
if (currentlyParsing == kVerticeInformation) {
if (currentParserTagType == kGeometry) {
//NSLog(#"Loaded Vertices %#", string);
NSArray * nums = [string componentsSeparatedByString:#" "];
culmunativeCount += [nums count];
//NSLog(#"Culm Count is %d", culmunativeCount);
[fullParseString appendString : string];
if (checkSumCount <= culmunativeCount) {
//NSLog(#"Full Parse String is %#", fullParseString);
NSArray * finishedArray = [fullParseString componentsSeparatedByString:#" "];
//NSLog(#"Finihsed ARray is %d", [finishedArray count]);
[finishedParsingArray addObjectsFromArray:finishedArray];
//NSLog(#" FINISHED PARSING = %d", [finishedParsingArray count]);
NSUInteger baseIndex;
for (baseIndex=0; baseIndex <[finishedParsingArray count]; baseIndex +=3) {
NSString * xPoint = [finishedParsingArray objectAtIndex:baseIndex];
NSDecimalNumber * errorCheckX = [NSDecimalNumber decimalNumberWithString:xPoint];
float x = [errorCheckX floatValue];
NSString * yPoint = [finishedParsingArray objectAtIndex:baseIndex +1];
NSDecimalNumber * errorCheckY = [NSDecimalNumber decimalNumberWithString:yPoint];
float y = [errorCheckY floatValue];
NSString * zPoint = [finishedParsingArray objectAtIndex:baseIndex+2];
NSDecimalNumber * errorCheckZ = [NSDecimalNumber decimalNumberWithString:zPoint];
float z = [errorCheckZ floatValue];
Vertex3D vertexItem = {x,y,z}
//NSLog(#"Vertices stored are %f, %f, %f", x,y,z);
}
currentlyParsing = kNilSetting;
checkSumCount = 0;
[finishedParsingArray removeAllObjects];
//[finishedArray release];
culmunativeCount = 0;
[fullParseString setString:#""];
}
}
}
}
As you can see, I am now creating a Vertex3D C Struct each time with the parsed vertice information.
My questions are :
How would I then create an array of these individual C Vertex3D structs ?
How can I then pass this array of structs to my sceneObject ?
Create Objective C wrapper class for your array. It can hold several arrays (e.g. vertices, normals and tangents). You know the array size beforehand, so you can preallocate the required amount of space:
#interface MYVertexArray : NSObject {
float* _mVerts;
float* _mNormals;
int _mCount;
}
#property(nonatomic, readonly) float* verts;
#property(nonatomic, readonly) float* norms;
/**
Here you're allocating your arrays (don't forget to free them is dealloc).
*/
-(id) initWithSize:(int) size;
#end
and then in cycle, you're just doing this:
MYVertexArray* my_vertex_data = [[MYVertexArray alloc] initWithSize: [finishedParsingArray count]];
for(int i=0; i<[finishedParsingArray count]; ++i) {
my_vertex_data.verts[i] = [[finishedParsingArray objectAtIndex: i] floatValue];
}

How to compare array element?

Suppose I have an array having elements "am","john","rosa","freedom". I want to compare these elements and result would be the word and the size of the longest word. I am using objective C.
There isn't a "built-in" way of doing this, however you can use NSArray's sortedArrayUsingSelector: and create a category on NSString to provide a lengthCompare: method.
// NSString+LengthCompare.h
#import NSString.h
#interface NSString (LengthComparison)
- (NSComparisonResult)lengthCompare:(NSString *)aString;
#end
// NSString+LengthCompare.m
#import NSString+LengthCompare.h
#implememtation NSString (LengthComparison)
- (NSComparisonResult)lengthCompare:(NSString *)aString
{
if ([self length] < [aString length]) {
return NSOrderedAscending;
} else if ([self length] > [aString length]) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}
#end
Now you can sort an of strings in ascending order using lengthCompare:
NSArray *array = [NSArray arrayWithObjects: #"am", #"john", #"rosa", #"freedom", nil];
NSArray *arraySortedByStringLength = [array sortedArrayUsingSelector:#selector(lengthCompare:)];
NString *shortestWord = [[arraySortedByStringLength objectAtIndex:0] retain];
NSLog(#"shortest word, %# has length %d", shortestWord, [shortestWord length];
[shortestWord release];
NString *longestWord = [[arraySortedByStringLength lastObject] retain];
NSLog(#"Longest word, %# has length %d", longestWord, [longestWord length];
[longestWord release];
Sounds like a classical logic exercise or is it something I miss in your question ?
int longestWordIndex = 0;
NSUInteger longestWordSize = 0;
for (int i=0 ; i<[nameArray count] ; i++) {
NSString* element = (NSString*)[nameArray objectAtindex:i];
if([element lenght] > longestWordSize) {
longestWordSize = [element lenght];
longestWordIndex = i;
}
}
NSLog("Longest word is %# with size of :%d", [nameArray objectAtIndex:longestWordIndex], longestWordSize);
I'll add one more approach to the two above -- use a block to do the body of your iteration.
__block NSUInteger longestWordSize = -1; // Make sure at least one object will be longer.
__block NSUInteger longestWordIndex;
[nameArray enumerateObjectsUsingBlock:^(id currentWord, NSUInteger index, BOOL *stop) {
if ([currentWord length] > longestWordSize) {
longestWordSize = [currentWord length];
longestWordIndex = index;
}
}];
NSLog("Longest word is %# with size of :%d", [nameArray objectAtIndex:longestWordIndex], longestWordSize);
Edit: The max and index have to be of storage type __block so they can be changed from inside the block.

How to find the median value of NSNumbers in an NSArray?

I'm trying to calculate the median of a (small) set of NSNumbers in an NSArray. Every object in the NSArray is a NSNumber.
Here is what I'm trying, but it's not working:
NSNumber *median = [smallNSArray valueForKeyPath:#"#median.floatValue"];
NSArray *sorted = [smallNSArray sortedArrayUsingSelector:#selector(compare:)]; // Sort the array by value
NSUInteger middle = [sorted count] / 2; // Find the index of the middle element
NSNumber *median = [sorted objectAtIndex:middle]; // Get the middle element
You can get fancier. For example, the median of a set with an even number of numbers is technically the average of the middle two numbers. You could also wrap this up into a neat one-line method in a category on NSArray:
#interface NSArray (Statistics)
- (id)median;
#end
#implementation NSArray (Statistics)
- (id)median
{
return [[self sortedArrayUsingSelector:#selector(compare:)] objectAtIndex:[self count] / 2];
}
#end
For anyone who has the unusual need for this function, here's a category method on NSArray that will work with both an odd and an even number of elements:
NSARRAY CATEGORY METHOD
- (float)median {
if (self.count == 1) return [self[0] floatValue];
float result = 0;
NSUInteger middle;
NSArray * sorted = [self sortedArrayUsingSelector:#selector(compare:)];
if (self.count % 2 != 0) { //odd number of members
middle = (sorted.count / 2);
result = [[sorted objectAtIndex:middle] floatValue];
}
else {
middle = (sorted.count / 2) - 1;
result = [[#[[sorted objectAtIndex:middle], [sorted objectAtIndex:middle + 1]] valueForKeyPath:#"#avg.self"] floatValue];
}
return result;
}
TEST
NSArray * singleElement = #[#1];
NSArray * oddNumberOfElements = #[#3, #5, #7, #12, #13, #14, #19, #20, #21, #22, #23, #29, #39, #40, #56];
NSArray * evenNumberOfElements = #[#3, #5, #7, #12, #13, #14, #19, #20, #21, #22, #23, #29, #40, #56];
NSLog(
#"oddNumberOfElements: %f, evenNumberOfElements: %f singleElement: %f",
[oddNumberOfElements median], [evenNumberOfElements median], [singleElement median]
);
//oddNumberOfElements: 20.000000, evenNumberOfElements: 19.500000 singleElement: 1.000000
Swift Extension
extension Array where Element: Comparable {
var median: Element {
return self.sort(<)[self.count / 2]
}
}

How to declare an array of floats as a class variable in Objective-C when the dimension is undefined at the class instantiation time?

In Java, it would look like this:
class Foo
{
float[] array;
}
Foo instance = new Foo();
instance.array = new float[10];
You can just use a pointer:
float *array;
// Allocate 10 floats -- always remember to multiple by the object size
// when calling malloc
array = (float *)malloc(10 * sizeof(float));
...
// Deallocate array -- don't forget to do this when you're done with your object
free(array);
If you're using Objective-C++, you could instead do:
float *array;
array = new float[10];
...
delete [] array;
Here's another way to do it. Create a NSMutableArray object and add NSNumber objects to it. It's up to you to decide whether or not this is sensible.
NSMutableArray *array;
array = [[NSMutableArray alloc] init];
[array addObject:[NSNumber numberWithFloat:1.0f]];
[array release];
Another way to do this in Objective-C is to use indexed instance variables:
#interface ArrayOfFloats : NSObject {
#private
NSUInteger count;
float numbers[0];
}
+ (id)arrayOfFloats:(float *)numbers count:(NSUInteger)count;
- (float)floatAtIndex:(NSUInteger)index;
- (void)setFloat:(float)value atIndex:(NSUInteger)index;
#end
#implementation ArrayOfFloats
+ (id)arrayOfFloats:(float *)numbers count:(NSUInteger)count {
ArrayOfFloats *result = [NSAllocateObject([self class], count * sizeof(float), NULL) init];
if (result) {
result->count = count;
memcpy(result->numbers, numbers, count * sizeof(float));
}
return result;
}
...
#end
For more see the documentation for NSAllocateObject(). A limitation of indexed instance variables is that you can't subclass a class that uses them.