I'm trying to create a gradient color out of an array of dictionary (colorArray2). This dictionary contains 5 keys: r, g, b, a, p. r, g, b, a are component values (strings), p being the location. I'm trying to create a gradient color with initWithColors:atLocations:colorSpace. For now, I have the following.
NSGradient *aGradient;
NSColorSpace *space = [NSColorSpace genericRGBColorSpace];
NSMutableArray *cArray = [[NSMutableArray alloc] initWithObjects:nil]; // storing colors
NSMutableArray *pArray = [[NSMutableArray alloc] initWithObjects:nil]; // storing locations
for (NSInteger i2 = 0; i2 < colorArray2.count; i2++) {
NSString *r = [[colorArray2 objectAtIndex:i2] objectForKey:key2a];
NSString *g = [[colorArray2 objectAtIndex:i2] objectForKey:key2b];
NSString *b = [[colorArray2 objectAtIndex:i2] objectForKey:key2c];
NSString *a = [[colorArray2 objectAtIndex:i2] objectForKey:key2d];
NSString *p = [[colorArray2 objectAtIndex:i2] objectForKey:key2e];
NSColor *color = [NSColor colorWithSRGBRed:[r integerValue]/255.0f green:[g integerValue]/255.0f blue:[b integerValue]/255.0f alpha:[a integerValue]/100.0f];
[cArray addObject:color];
[pArray addObject:[NSNumber numberWithDouble:[p doubleValue]]];
}
So I have an array (cArray) containing colors. What I don't know is how to create an array of locations. According to the documentation, locations is an array of CGFloat values containing the location for each color in the gradient. How do I enumerate whatever to create a float array?
Thank you for your help.
Update
More specifically, how do I make pArray to get something like
double d[] = {0.1, 0.2, 0.3, 0.5, 1.0};
so that I can have
aGradient = [[NSGradient alloc] initWithColors:cArray atLocations:d colorSpace:space];
NSGradient's documentation states that locations parameter should be of type const CGFloat*, so you can't use NSArray*. The following should work:
// Allocate a C-array with the same length of colorArray2
CGFloat* pArray = (CGFloat*)malloc(colorArray2.count * sizeof(CGFloat));
for (NSInteger i2 = 0; i2 < colorArray2.count; i2++) {
// Extract location
NSString* p = [[colorArray2 objectAtIndex:i2] objectForKey:key2e];
pArray[i2] = [p doubleValue];
}
// Do whaterver with pArray
...
// Remember to free it
free(pArray);
You can use:
NSArray *colors = #[[NSColor colorWithWhite:.3 alpha:1.0],
[NSColor colorWithWhite:.6 alpha:1.0],
[NSColor colorWithWhite:.3 alpha:1.0]];
CGFloat locations[3] = {0.0, 0.5, 1.0};
NSGradient *gradient = [[NSGradient alloc] initWithColors:colors atLocations:locations colorSpace:[NSColorSpace genericRGBColorSpace]];
[gradient drawInRect:CGRectMake(100.0, 7.0, 10.0, 18.0) angle:-90];
To the other answers: no. Just no.
Actual answer:
How do I make an array of CGFloats in objective c?
First of all, this is Objective-C, not C. Technically you can use malloc, but that's a really terrible hack. You should convert to an NSNumber and then you can populate the NSArray. After, you can convert back using NSNumber's floatValue method. This way is proper Objective-C. Mixing and matching C and Obj-C just creates spaghetti code which is hard to read and eventually becomes unmaintainable.
I got it.
NSInteger count,index;
double *dArray;
count = pArray.count;
dArray = (double *) malloc(sizeof(double) * count);
for (index = 0; index < count; index++) {
dArray[index] = [[pArray objectAtIndex:index] floatValue];
}
aGradient = [[NSGradient alloc] initWithColors:cArray atLocations:dArray colorSpace:space];
Related
I'm currently trying to add more than one mathematical function curves. Below is part of my code.
// draw all expression curves (in viewDidLoad)
for ( j=0; j<self.expNum; j++ ) {
[self getDataForPlot1:self.plotIndex]; // get DataForPlot of one selected expression
[self addCurve:self.plotIndex];
}
I'm trying to add all curves after drawing the axes, but it is only the last input curve that is drawn. How can I separate the dataForPlot for each function?
-(void)getDataForPlot1:(int)index
{
int i;
NSString *exp;
int bound, plotNum;
double interval;
bound = 3 * scaleX;
plotNum = 3 * 60;
interval = (double)bound / plotNum;
NSMutableArray *contentArray = [NSMutableArray arrayWithCapacity:2*plotNum];
for ( i = -plotNum; i < plotNum; i++ ) {
id x;
x = [NSNumber numberWithFloat: i * interval];
// get one expression
.......
id y = [exp numberByEvaluatingString]; // get y values from the expression
[contentArray addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:x, #"x", y, #"y", nil]];
}
dataForPlot = contentArray;
}
-(void)addCurve:(int)index {
CPTScatterPlot *boundLinePlot = [[CPTScatterPlot alloc] init];
CPTMutableLineStyle *lineStyle = [CPTMutableLineStyle lineStyle];
lineStyle.miterLimit = 1.0f;
lineStyle.lineWidth = 3.0f;
lineStyle.lineColor = [CPTColor blueColor];
boundLinePlot.dataLineStyle = lineStyle;
boundLinePlot.identifier = #"Blue Plot";
boundLinePlot.dataSource = self;
[graph addPlot:boundLinePlot toPlotSpace:plotSpace];
boundLinePlot.interpolation = CPTScatterPlotInterpolationCurved;
}
(Answering the question based on comments above)
Save a copy of each dataset separately. It looks like the calculated plot data gets overwritten each time you call -getDataForPlot1:.
Also, set a unique identifier for each plot so the datasource can know which one is requesting data.
My question is simple, I have the following code, it creates an array of Hues got from a function that returns the UIColor of an image (this is not important, just context). So, I need to create this array as fast as possible, this test runs with only a 5x5 pixels image and it takes about 3sec, I want to be able to run a 50x50 pixels image (at least) in about 2 secods (tops), any ideas?
- (void)createArrayOfHues: (UIImage *)imageScaned{
if (imageScaned != nil) {
NSLog(#"Creating Array...");
UIImageView *img = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 5, 5)];
img.contentMode = UIViewContentModeScaleToFill;
img.image = imageScaned;
img.contentMode = UIViewContentModeRedraw;
img.hidden = YES;
int i = 0;
CGFloat hue = 0;
CGFloat sat = 0;
CGFloat brit = 0;
CGFloat alph = 0;
CGFloat hue2 = 0;
CGFloat sat2 = 0;
CGFloat brit2 = 0;
CGFloat alph2 = 0;
[_colorsArray removeAllObjects];
[_satForHue removeAllObjects];
[_britForHue removeAllObjects];
[_alphForHue removeAllObjects];
_colorsArray = [[NSMutableArray alloc] initWithCapacity:(25)];
_satForHue = [[NSMutableArray alloc] initWithCapacity:(25)];
_britForHue = [[NSMutableArray alloc] initWithCapacity:(25)];
_alphForHue = [[NSMutableArray alloc] initWithCapacity:(25)];
while (i<25) {
for (int y=1; y <= 5; y++){
for (int x = 1; x <= 2.5; x++){
if (x != (5-x)){
UIColor *color = [self colorMatch:imageScaned :x :y];
UIColor *color2 = [self colorMatch:imageScaned :(5-x) :y];
if([color getHue:&hue saturation:&sat brightness:&brit alpha:&alph] && [color2 getHue:&hue2 saturation:&sat2 brightness:&brit2 alpha:&alph2]){
NSNumber *hueId = [NSNumber numberWithFloat:(float)hue];
NSNumber *satId = [NSNumber numberWithFloat:(float)sat];
NSNumber *britId = [NSNumber numberWithFloat:(float)brit];
NSNumber *alphId = [NSNumber numberWithFloat:(float)alph];
NSNumber *hueId2 = [NSNumber numberWithFloat:(float)hue2];
NSNumber *satId2 = [NSNumber numberWithFloat:(float)sat2];
NSNumber *britId2 = [NSNumber numberWithFloat:(float)brit2];
NSNumber *alphId2 = [NSNumber numberWithFloat:(float)alph2];
[_colorsArray insertObject:hueId atIndex:i];
[_satForHue insertObject:satId atIndex:i];
[_britForHue insertObject:britId atIndex:i];
[_alphForHue insertObject:alphId atIndex:i];
[_colorsArray insertObject:hueId2 atIndex:(i+1)];
[_satForHue insertObject:satId2 atIndex:(i+1)];
[_britForHue insertObject:britId2 atIndex:(i+1)];
[_alphForHue insertObject:alphId2 atIndex:(i+1)];
}
NSLog(#"color inserted at %i with x: %i and y: %i" , i , x, y);
i++;
}else {
UIColor *color = [self colorMatch:imageScaned :x :y];
if([color getHue:&hue saturation:&sat brightness:&brit alpha:&alph]){
NSNumber *hueId = [NSNumber numberWithFloat:(float)hue];
NSNumber *satId = [NSNumber numberWithFloat:(float)sat];
NSNumber *britId = [NSNumber numberWithFloat:(float)brit];
NSNumber *alphId = [NSNumber numberWithFloat:(float)alph];
[_colorsArray insertObject:hueId atIndex:i];
[_satForHue insertObject:satId atIndex:i];
[_britForHue insertObject:britId atIndex:i];
[_alphForHue insertObject:alphId atIndex:i];
}
}
}
}
}
NSLog(#"Returns the array");
}else{
NSLog(#"Returns nothing");
}
}
The code for colorMatch:
- (UIColor *) colorMatch: (UIImage *)image :(int) x :(int) y {
isBlackColored = NO;
if (image == nil){
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
BOOL customColor = [defaults boolForKey:#"custom_color"];
if (customColor){
float red = [defaults floatForKey:#"custom_color_slider_red"];
float green = [defaults floatForKey:#"custom_color_slider_green"];
float blue = [defaults floatForKey:#"custom_color_slider_blue"];
return [UIColor colorWithRed:red green:green blue:blue alpha:1];
}else
isDefaultS = YES;
}
else{
CFDataRef pixelData = CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
const UInt8* data = CFDataGetBytePtr(pixelData);
int pixelInfo = ((image.size.width * y) + x ) * 4;
UInt8 red = data[pixelInfo];
UInt8 green = data[(pixelInfo + 1)];
UInt8 blue = data[pixelInfo + 2];
UInt8 alpha = data[pixelInfo + 3];
CFRelease(pixelData);
float redC = red/255.0f;
float greenC = green/255.0f;
float blueC = blue/255.0f;
UIColor* color = [UIColor colorWithRed:redC green:greenC blue:blueC alpha:alpha/255.0f];
return color;
}
return nil;
}
I think your main performance bottleneck is not the initialization of NSMutableArray instances, but the way you index your image:
UIColor *color = [self colorMatch:imageScaned :x :y];
I guess this method converts the UIImage to a CGImageRef, copies its data, indexes it, then destroys/releases these temporary objects, or something like this - for every single pixel...
You should refactor this code to get hold of the image buffer only once, and then work with it like a regular C pointer/array. If that doesn't solve your performance problem, you should do some profiling.
I am parsing this JSON file (correctly, it works with the UITextFields):
{"longitude":["37.786793","39.388528"],"latitude":["-122.395416","-78.887734"]}
ind creating MapViews, with the respective annotations in this way:
NSArray *allKeys2 = [DictionaryMap allKeys];
for (int h = 0; h < [allKeys2 count]; h++) {
CGRect mapFrame = CGRectMake( 400, e, 200, 110);
MKMapView *mapView2 = [[MKMapView alloc] initWithFrame:mapFrame];
[image1 addSubview:mapView2];
NSString *key2 = [allKeys2 objectAtIndex:i];
NSObject *obj2 = [DictionaryMap objectForKey:key2];
NSString *address = [NSString stringWithFormat:#"%#", obj2];
float stringFloat = [address floatValue];
float stringFloat2 = [key2 floatValue];
CLLocationCoordinate2D anyLocation;
anyLocation.longitude = stringFloat;
anyLocation.latitude = stringFloat2;
MKPointAnnotation *annotationPoint2 = [[MKPointAnnotation alloc] init]; annotationPoint2.coordinate = anyLocation;
annotationPoint2.title = #"Event";
annotationPoint2.subtitle = #"Microsoft's headquarters2";
[mapView2 addAnnotation:annotationPoint2];
[mapView2.userLocation setTitle:#"I am here"];
[mapView2.userLocation addObserver:self
forKeyPath:#"location"
options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld)
context:NULL];
[mapView2 setShowsUserLocation:NO];
[MapViewArray addObject:mapView2];
if (MapViewArray == nil)MapViewArray = [[NSMutableArray alloc]init];
[MapViewArray addObject: mapView2];
}}
}while(g < f);
...I want the first map view to show the first coordinate pin, and the second to show the second pair of coordinates. But now, it is plotting on all the map views the same pin, corresponding to the last coordinates, and not to the first and second... respectively. This method works for the UITextField text, so I can't find the problem.
Please help!!
EDIT:
NSString *filenameMap = [NSString stringWithFormat:#"%#%#Map", destDir, NavBar.topItem.title];
NSString *MapPath = [documentsDirectory stringByAppendingPathComponent:[NSString stringWithFormat:#"%#Map", NavBar.topItem.title]];
[self.restClient loadFile:filenameMap intoPath:MapPath];
NSString *fileContentMap = [[NSString alloc] initWithContentsOfFile:MapPath];
SBJsonParser *parserMap = [[SBJsonParser alloc] init];
NSDictionary *dataMap = (NSDictionary *) [parserMap objectWithString:fileContentMap error:nil];
NSArray *MaparrayLongitude = [dataMap objectForKey:#"longitude"];
NSArray *MaparrayLatitude = [dataMap objectForKey:#"latitude"];
NSDictionary* DictionaryMap = [NSDictionary dictionaryWithObjects:MaparrayLatitude forKeys:MaparrayLongitude];
Another take:
You probably don't want to map your latitudes to longitudes in DictionaryMap. How about making an NSArray of NSDictionaries, where each dictionary has a "latitude" key and a "longitude" key?
Also, you have "[MapViewArray addObject: mapView2]" twice in your code.
And what is "g"? Maybe add some logging to your loop so you can see what's being created?
I’ve recently stuck at a problem. Here is the thing, I’m trying to get a float object from NSArray that holds it, and all I can get is (null). Obviously not the thing that I want to receive. Look at the snippet of code:
h = [[NSMutableArray alloc] initWithObjects:[NSNumber numberWithFloat:1.0],[NSNumber numberWithFloat:1.0],[NSNumber numberWithFloat:1.0], nil];
x = [[NSMutableArray alloc] initWithObjects:[NSNumber numberWithFloat:1.0],[NSNumber numberWithFloat:2.0], nil];
y = [[NSMutableArray alloc] init];
int step = 15; // That is just a random value, will depend on size of h and x.
for (int i = 0; i < step; ++i) {
NSLog(#"step = %i", i);
NSMutableArray *xTemp = [[NSMutableArray alloc] initWithArray:x];
NSMutableArray *hTemp = [[NSMutableArray alloc] initWithArray:h];
for (int j = 0; j < 3; ++j) {
float xToMul = [[xTemp objectAtIndex:j] floatValue];
float hToMul = [[hTemp objectAtIndex:(j+i)] floatValue];
NSLog(#"xToMul = %#", xToMul);
NSLog(#"hToMul = %#", hToMul);
}
NSLog(#"\n");
}
And the resul is:
xToMul = (null)
hToMul = (null)
and all I need those values is to do some easy math.
Thanks.
M.R.
Here's your problem:
float xToMul = [[xTemp objectAtIndex:j] floatValue]; float hToMul = [[hTemp objectAtIndex:(j+i)] floatValue];
NSLog(#"xToMul = %#", xToMul); NSLog(#"hToMul = %#", hToMul);
%# is for objects that support -description. float is not an object at all. This code sends the float a -description message, which it can't respond to.
There's two ways to solve this.
The first is to make xToMul and hToMul objects instead of floats and keep the format string.
id xToMul = [xTemp objectAtIndex:j];
id hToMul = [hTemp objectAtIndex:(j+i)];
NSLog(#"xToMul = %#", xToMul);
NSLog(#"hToMul = %#", hToMul);
The second is to keep them as floats but fix the format string:
float xToMul = [[xTemp objectAtIndex:j] floatValue];
float hToMul = [[hTemp objectAtIndex:(j+i)] floatValue];
NSLog(#"xToMul = %f", xToMul);
NSLog(#"hToMul = %f", hToMul);
If you're planning to do math with the floats, you probably want to pick this option.
Another interesting point is this loop:
for (int j = 0; j < 3; ++j) {
This will step through j with three values: 0, 1 and 2. That corresponds to the first, second and third item in NSArray. You have two items in x and three in h. I'm guessing this is just a simplification of your original code, but in both cases it's one short. j of 2+1 will access the 4th item in h, and j of 2 will access the 3rd item in x.
I'm trying to figure out how to take the individual characters in an NSString object and create UILabels from them, with the UILabel text set to the individual character.
I'm new to Cocoa, but so far I have this...
NSString *myString = #"This is a string object";
for(int i = 0; i < [myString length]; i++)
{
//Store the character
UniChar chr = [myString characterAtIndex:i];
//Stuck here, I need to convert character back to an NSString object so I can...
//Create the UILabel
UILabel *lbl = [[UILabel alloc] initWithFrame....];
[lbl setText:strCharacter];
//Add the label to the view
[[self view] addSubView:lbl];
}
Aside from where I'm stuck, my approach already feels very hackish, but I'm a noob and still learning. Any suggestions for how to approach this would be very helpful.
Thanks so much for all your help!
You want to use -substringWithRange: with a substring of length 1.
NSString *myString = #"This is a string object";
NSView *const parentView = [self superview];
const NSUInteger len = [myString length];
for (NSRange r = NSMakeRange(0, 1); r.location < len; r.location += 1) {
NSString *charString = [myString substringWithRange:r];
/* Create a UILabel. */
UILabel *label = [[UILabel alloc] initWithFrame....];
[lbl setText:charString];
/* Transfer ownership to |parentView|. */
[parentView addSubView:label];
[label release];
}