Binding Patch Input

jay.kickliter's picture

This is driving me crazy. I've read all the Apple documentation regaurding Quartz programming, and cant figure it out.

I have a class AppController, a QCView and QCPatchController. I want to bind the inputs "pitch" and "roll" inputs for the Quartz Composistion to "pitch" and "roll" in AppController. So whenever "pitch" or "roll" gets updated, the QC will get updated also.

As a test, I am able to move the QC sphere around by binding NSSliders to the QCPatchController through "patch.pitch.value" and "patch.roll.value", but nothing happens when I try to bind AppController to those inputs. Except, AppController does get updated if I change the QC's inputs values directly through the NSSliders, but not the other way around. All I want is to rotate a sphere about two axis, if anyone has any advice, it would be great.

Here's some of the code:


#import <Cocoa/Cocoa.h>
#import "AMSerialPort.h"
#import <Quartz/Quartz.h>
@class PreferenceController;
@interface AppController : NSObject {
   IBOutlet NSTextField               *inputTextField;
   IBOutlet NSTextView                  *outputTextView;
   IBOutlet NSComboBox                  *speedComboBox;
   IBOutlet NSComboBox                  *deviceComboBox;
   IBOutlet NSButton                     *connectDisconnectButton;
   IBOutlet NSWindow                     *mainWindow;
   IBOutlet NSWindow                     *consoleWindow;
   IBOutlet NSButton                     *consoleWindowShowHideButton;
   IBOutlet NSProgressIndicator   *connectionIndicator;
   IBOutlet id                              patchController;
   AMSerialPort                           *port;
   NSArray                                    *speedArray;
   NSMutableData                           *buffer;
   NSMutableData                           *recordSeparator;
   PreferenceController               *preferenceController;
   float                                       pitch;
   float                                       roll;
   float                                       a2pitch;
   float                                       a2roll;
   float                                       qbPitch;
   float                                       qbRoll;
   float                                       ratePitch;
   float                                       rateRoll;
   float                                       yRate;
   float                                       xRate;
   float                                       xAxis;
   float                                       yAxis;
   float                                       zAxis;   
- (AMSerialPort *)port;
- (void)setPort:(AMSerialPort *)newPort;
- (void)explodeRecord:(NSData *)record;
- (float)pitch;
- (void)setPitch:(float)ptch;
- (float)roll;
- (void)setRoll:(float)rll;
- (float)a2Pitch;
- (void)setA2Pitch:(float)a2ptch;
- (float)a2Roll;
- (void)setA2Roll:(float)a2ptch;
- (float)qbPitch;
- (void)setQbPitch:(float)qbptch;
- (float)qbRoll;
- (void)setQbRoll:(float)qbrll;
- (float)ratePitch;
- (void)setRatePitch:(float)rtptch;
- (float)rateRoll;
- (void)setRateRoll:(float)rtrll;
- (float)yRate;
- (void)setYRate:(float)xrt;
- (float)xRate;
- (void)setXRate:(float)yrt;
- (float)xAxis;
- (void)setXAxis:(float)xaxs;
- (float)yAxis;
- (void)setYAxis:(float)yaxs;
- (float)zAxis;
- (void)setZAxis:(float)zaxs;
- (IBAction)send:(id)sender;
- (IBAction)clearOutputTextView:(id)sender;
- (IBAction)connectDisconnect:(id)sender;
- (IBAction)consoleWindowShowHide:(id)sender;
- (IBAction)showPreferencePanel:(id)sender;

AppController.m (abridged)

- (void)awakeFromNib
   // register for port add/remove notification
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didAddPorts:) name:AMSerialPortListDidAddPortsNotification object:nil];
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didRemovePorts:) name:AMSerialPortListDidRemovePortsNotification object:nil];
   // register for notifications of user changing baud rade from the combo box
   [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(didSelectSpeed:) name:NSComboBoxSelectionDidChangeNotification object:speedComboBox]; // I'd to move this to a delegate method, since there will probably wind up being a bunch of combo boxes, but the delegate method doesn't seem to specify which combo box was selected
   [AMSerialPortList sharedPortList]; // initialize port list to arm notifications
   [outputTextView setFont:[NSFont fontWithName:@"Monaco" size:10]];
   [outputTextView setTextColor:[NSColor greenColor]];
   [outputTextView setBackgroundColor:[NSColor blackColor]];
   NSMutableDictionary*  options;
   options = [NSMutableDictionary new];
   [options setObject:[NSNumber numberWithBool:NO] forKey:@"NSConditionallySetsEnabled"];
   [options setObject:[NSNumber numberWithBool:NO] forKey:@"NSRaisesForNotApplicableKeys"];
   [self bind:@"pitch" toObject:patchController withKeyPath:@"patch.pitch.value" options:options];
   [self bind:@"roll" toObject:patchController withKeyPath:@"patch.roll.value" options:options];
   [options release];
- (void)setPitch:(float)ptch
   pitch = ptch;
- (float)pitch
   return pitch;
- (float)roll
   return roll;
- (void)setRoll:(float)rll
   roll = rll;

.lov.'s picture

hmm, could you upload the whole project somewhere?

jay.kickliter's picture
here's the source

I attached the source. The program is meant to attach to a microcontroller via serial. If you can see anything I can't that would be awesome. I've been trying to figure this out for a few days.

PropStream-IMU.zip2.64 MB

.lov.'s picture
no serial

i cannot test is because i don't have any serial port device.


I can't figure out, what would you like exactly. When changing axis, send the new roll and pitch to the compositions, or... ?

dust's picture
serial flight

looks like your trying to build some sort of flight simulator ? i had a go at binding patches the other day in interface builder, for some reason i would follow the developer documentation but simple binding wasn't working like expected. someone forwarded me this line of code. apparently the documentation and the code for things like event forwarding are known bugs... this helped me....

@implementation AppController - (void) awakeFromNib { [qcView setEventForwardingMask :NSAnyEventMask]; }

not sure if it would help you. i would use a kineme serial in patch and parse out the data in qc then bind or forward the data to your interface, but thats just me, chris did all the hard work all ready. you probably need to keep everything objective c though, you got more control , and portability that way.

the last day i have been messing with a micro-controller as well. not sure how all this background, and buffing works in objective c, i usually have to delay the read a bit or i get inaccurate results.

wish i could help...i haven't messed with coding accelerometers and stuff yet still messing with potentiometers.

jay.kickliter's picture
thanks for the pointer

dust, I'll try that.

In the mean time, someone on the Cocoadev mailing list told me to try:

[patchController setValue:[NSNumber numberWithFloat:roll] forKeyPath:@"patch.roll.value"];

which worked. I had given up on using bindings.

This isn't for a flight sim. I'm just interfacing with a Propeller chip (8 cores, awesome), and a Sparkfun 5 Degree of Freedom gyro/accellorometer. I'm thinking of doing a UAV type project. But in the meantime, I'm just relearning some Cocoa and Quartz.

Picture 1.png
Picture 1.png459.23 KB

jay.kickliter's picture


Forgot to tell you. I'm using AMSerialPort class from I started off using the Kineme Serial patch for quick prototyping, but I couldn't process data as fast as I wanted to. Now, I'm running at up to 230400 bps, with minimal latency. AMSerialPort makes background serial really easy. It just calls a delegate method when data comes in.