How can I create an instance of NSValue that contains a CGAffineTransform?
UIKit provides [NSValue valueWithCGAffineTransform:], but AppKit does not.
Do I need to use the valueWithBytes:objCType: static method?
CGAffineTransform is a struct
struct CGAffineTransform {
CGFloat a, b, c, d;
CGFloat tx, ty;
};
The correct way how to handle structs is mentioned in Key-Value Coding Programming Guide - Representing Non-Object Values (Wrapping and Unwrapping Structures)
CGAffineTransform transform;
NSValue *value = [NSValue valueWithBytes:&transform objCType:#encode(CGAffineTransform)];
Related
I am trying to parse an array of Vectors (from C++'s std::vector) to an NSMutableArray of NSNumber. However, the Vector that I add to the NSNumber array is always nil, even after adding a NSNumber (parsed from std::vector)
In this project, I'm trying to connect the OpenCV Canny Edge Detection Algorithm (C++) to my Swift project. One of their methods returns all the photo's edges as std::vector. So, I'm trying to parse this into an array that is compatible with Swift (using Objective-C++ as the intermediary language). As of right now, it seems that only one line isn't working correctly (as stated above).
I am also a beginner Objective-C++ programmer, so there may be some common errors in the code, which I haven't found.
/*Ptr<LineSegmentDetector>*/
cv::Ptr<cv::LineSegmentDetector> ls = cv::createLineSegmentDetector(cv::LSD_REFINE_STD) ;//Creates the line detector (AKA what I called the edge detector)
std::vector<cv::Vec4f> lines_std;
[image convertToMat: &mat];
// Detect the lines
ls->detect(mat, lines_std);
//Swift compatible NSMutableArray to return from this method
NSMutableArray *edgeLines;
printf("currently finding the edge lines");
for (int i = 0; i < lines_std.size(); i ++) {
NSMutableArray<NSNumber *> *vector;
//Convert from Vec4f to NSNumber
for (int k = 0; k < 4; k ++) {
[vector addObject: [NSNumber numberWithFloat: (lines_std[i][k])]]; //HERE, I'm parsing each float value in each vector (from std::vector<cv::Vec4f>) and adding it to a NSArray, like a vector
}
//Here, I add the vectors to the return NSMutable array
[edgeLines insertObject:vector atIndex:edgeLines.count];
}
return edgeLines;
As stated above, the "vector" variable is always nil, even though I'm adding an NSNumber object to it.
I found the problem, I hadn't used this line:
NSMutableArray *vector = [[NSMutableArray alloc] init];
It's been a while, as I was hospitalized for 3 months after a motorcycle accident.
So I just got to renew my apple programming subscription :-)
I have another question that has been on my mind for quite some time.
In my iPad application I draw a triangle in the center of an iPad like this:
- (void)initTriangle
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
// draw triangle (TRIANGLE)
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path,NULL, 0.5*screenWidth, 0.5*screenHeight-25);
CGPathAddLineToPoint(path, NULL, 0.5*screenWidth-25, 0.5*screenHeight+25);
CGPathAddLineToPoint(path, NULL, 0.5*screenWidth+25, 0.5*screenHeight+25);
CGPathAddLineToPoint(path, NULL, 0.5*screenWidth, 0.5*screenHeight-25);
CAShapeLayer *triangle = [CAShapeLayer layer];
[triangle setPath:path];
[triangle setFillColor:[[UIColor blackColor] CGColor]];
[[[self view] layer] addSublayer:triangle];
CGPathRelease(path);
}
And I call this from my viewDidLoad like this:
[self initTriangle];
Now I'm trying to rotate this triangle with the rotation of my iPad around Z-Axis while laying flat on the table. I have a function that gives me the yaw readings in float and I'm calling my
-(void)updateTriangleWithYaw:(float)yaw
method, but I don't know what to exactly put in there to make it rotate.
here is what my method looks like so far:
-(void)updateTriangleWithYaw:(float)yaw
{
CGRect screenBound = [[UIScreen mainScreen] bounds];
CGSize screenSize = screenBound.size;
CGFloat screenWidth = screenSize.width;
CGFloat screenHeight = screenSize.height;
NSLog(#"YAW: %f", yaw);
Z += 2 * yaw;
Z *= 0.8;
CGFloat newR = R + 10 * yaw;
self.triangle.frame = CGRectMake(0.5*screenWidth, 0.5*screenHeight, newR, newR);
}
Any help will be greatly appreciated!
Thanks and be safe guys!!
You should set the layer's affineTransform. You can apply a rotation transform like:
[self.triangle setAffineTransform:CGAffineTransformMakeRotation(yaw)];
This method, setAffineTransform is a convenience to set the transform property of the layer, which is a more general type of transform CATransform3D. You can also set the transform of the layer directly, and if you want to do that you can make a rotation about the z-axis like:
self.triangle.transform = CATransform3DMakeRotation(yaw, 0, 0, 1);
In this case the first argument is the angle (in radians) and the last three arguments specify the axis of rotation.
Note that you should not assign or depend on the value of the frame property of a layer whose transform is not the identity (CGAffineTransformIdentity). When you use the transform property you should set the size and position of your layer by assigning the layer's center and bounds properties, and similarly you should read the center and bounds when you want to find out information about the layer's position and size.
- (void) GetClientRect
NSArray *screenArray = [NSScreen screens];
NSScreen *mainScreen = [NSScreen mainScreen];
unsigned screenCount = [screenArray count];
unsigned index = 0;
for (index; index < screenCount; index++)
{
NSScreen *screen = [screenArray objectAtIndex: index];
NSRect screenRect = [screen visibleFrame];
NSString *mString = ((mainScreen == screen) ? #"Main" : #"not-main");
NSLog(#"Screen #%d (%#) Frame: %#", index, mString, NSStringFromRect(screenRect));
}
}
Above method is use to get frame for mainscreen.
But i want method which return Screen size of NSWindow whose kCGWindowNumber have been passed.
Any idea ?!
Why are you working with a CGWindowID (which is what I assume you meant by kCGWindowNumber)? That's a very unnatural thing to do in most circumstances.
Anyway, you can call CGWindowListCopyWindowInfo(0, theWindowID) and examine the dictionary in the first element of the returned array. Use the key kCGWindowBounds to get a dictionary representation of the bounds rectangle and then CGRectMakeWithDictionaryRepresentation() to convert that to a CGRect.
Are you looking for how to convert the NSWindow -frame, which is in Cocoa's coordinate system, to the Core Graphics coordinate system? The Cocoa coordinate system has its origin at the bottom-left of the primary display, with Y increasing in the up direction. The Core Graphics coordinate system has its origin at the top-left of the primary display, with Y increasing in the down direction.
So, the conversion looks like this:
NSWindow* window = /* ... comes from wherever ... */;
NSRect frame = window.frame;
frame.origin.y = NSMaxY([NSScreen.screens.firstObject frame]) - NSMaxY(frame);
CGRect cgbounds = NSRectToCGRect(frame);
I have a problem with CPTBarPlot in Core Plot on Cocoa.
Namely, I cannot achieve to control step width of bars. X-Axis ticks are set normally as integer from 1 to infinite and drawing Scatter Plot on it works.
However, when bar plot is drawn, only first columns starts (with proper offset, of course) on first tick. Second is a bit further form its tick, so is third and all others as shown on screenshot:
I haven't found any property to control this, however, I found that data source method
-(NSNumber *)numberForPlot:(CPTPlot *)plot field:(NSUInteger)fieldEnum recordIndex:(NSUInteger)index
Behaves differently than when I draw Scatter Plot. namely, it enumerates only integer 3, which is CPTBarPlotBindingBarTips and doesn't enumerate any other constant, I am especially bothered with absence of CPTBarPlotBindingBarLocations.
If I start VerticalBarChart from Plot Gallery mac demo project I've checked and seen that same method enumerates 3,4 and 2 constants in same order.
I am using Core Plot 0.9 namely, I believe the same as in this demo. Still...
How to solve this?
Here is the complete code for labels and ticks on X axis;
x.labelRotation = M_PI/4;
x.labelingPolicy = CPTAxisLabelingPolicyNone;
x.labelOffset = 0.0;
CPTMutableTextStyle *labelStyle = [CPTMutableTextStyle textStyle];
labelStyle.fontSize = 9.0;
x.labelTextStyle = labelStyle;
// NSMutableArray *dateArray = [dataSeries objectAtIndex:0];
NSMutableArray *customTickLocations = [NSMutableArray array];
NSMutableArray *xAxisLabels = [NSMutableArray array];
for (int i=0;i<[dataSeries count];i++) {
[customTickLocations addObject:[NSDecimalNumber numberWithInt:i+1]];
[xAxisLabels addObject:[dataSeries objectAtIndex:i]];
}
// [customTickLocations addObject:[NSDecimalNumber numberWithInt:[dateArray count]]];
NSUInteger labelLocation = 0;
NSMutableArray *customLabels = [NSMutableArray arrayWithCapacity:[xAxisLabels count]];
for (NSNumber *tickLocation in customTickLocations) {
CPTAxisLabel *newLabel = [[CPTAxisLabel alloc] initWithText: [xAxisLabels objectAtIndex:labelLocation++] textStyle:x.labelTextStyle];
newLabel.tickLocation = [tickLocation decimalValue];
newLabel.offset = x.labelOffset + x.majorTickLength;
newLabel.rotation = M_PI/4;
[customLabels addObject:newLabel];
[newLabel release];
}
[x setMajorTickLocations:[NSSet setWithArray:customTickLocations]];
x.axisLabels = [NSSet setWithArray:customLabels];
I have to add that same ticks are being used when scatter plot is drawn on same plot space and it matches perfectly....
The field parameter will be one of the members of this enum:
typedef enum _CPTBarPlotField {
CPTBarPlotFieldBarLocation = 2, ///< Bar location on independent coordinate axis.
CPTBarPlotFieldBarTip = 3, ///< Bar tip value.
CPTBarPlotFieldBarBase = 4 ///< Bar base (used only if barBasesVary is YES).
} CPTBarPlotField;
If the plot's plotRange property is nil (the default), the plot will ask the datasource for locations and tips for each bar. If barBasesVary == YES, it will also ask for base values for each bar.
Greetings,
I'm trying to draw a circle on a map. all the separate pieces of this project work independently but when I put them all together it breaks.
I setup my UI in my viewDidLoad, retaining most of it.
I then use touch events to call a my refresh map method:
-(void)refreshMap{
NSString *thePath = [NSString stringWithFormat:#"http://maps.google.com/staticmap?center=%f,%f&zoom=%i&size=640x640&maptype=hybrid",viewLatitude, viewLongitude, zoom];
NSURL *url = [NSURL URLWithString:thePath];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *mapImage = [[UIImage alloc] initWithData:data];
mapImage = [self addCircle:(mapImage) influence:(70) latCon:(320) lonCon:(320)];
NSLog(#"-- mapimageview retaincount %i",[mapImage retainCount]);
mapImageView.image = mapImage;
[mapImage release];}
Setup like this it will load the map with a circle once, but if the map is refreshed again it crashes.
If I comment out the mapImage release it works repeatedly but causes a memory leak.
The addCircle method I'm using:
-(UIImage *)addCircle:(UIImage *)img radius:(CGFloat)radius latCon:(CGFloat)lat lonCon:(CGFloat)lon{
int w = img.size.width;
int h = img.size.height;
lon = h - lon;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, w, h, 8, 4 * w, colorSpace, kCGImageAlphaPremultipliedFirst);
//draw the circle
CGContextDrawImage(context, CGRectMake(0, 0, w, h), img.CGImage);
CGRect leftOval = {lat- radius/2, lon - radius/2, radius, radius};
CGContextSetRGBFillColor(context, 0.0, 0.0, 1.0, 0.3);
CGContextAddEllipseInRect(context, leftOval);
CGContextFillPath(context);
CGImageRef imageMasked = CGBitmapContextCreateImage(context);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return [UIImage imageWithCGImage:imageMasked];}
Any insight/advise is greatly appreciated!
UIImage *mapImage = [[UIImage alloc] initWithData:data];
mapImage = [self addCircle:(mapImage) influence:(70) latCon:(320) lonCon:(320)];
That's not good. You're losing the reference to the contents of mapImage when you reassign it on the second line. The easiest way to fix this if probably to just add an additional variable, so you can keep track of both images.