Re: Creating a radar sweep effect

2009-09-28 Thread Alastair Houghton

On 27 Sep 2009, at 07:50, Graham Cox wrote:

One possibility is to use OpenGL. It has a history buffer mode  
(may not be called that - I forget exactly) that stores the previous  
image at a diminished brightness and that can be stacked for a  
series of frames, giving a fade or trail effect.


I think you're referring to the accumulation buffer, which can be used  
for this kind of thing.


That's probably the best way to implement this, to be honest.  Failing  
that, you could use Core Image (assuming that's an option for you).


Kind regards,

Alastair.

--
http://alastairs-place.net



___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Creating a radar sweep effect

2009-09-28 Thread douglas welton

Hi Guys,

Seems to me that CIImageAccumulator would be a possible solution for  
this problem.  Here's a pointer to the programming guide section for  
dynamical systems:


	http://developer.apple.com/mac/library/documentation/GraphicsImaging/Conceptual/CoreImaging/ci_tasks/ci_tasks.html#//apple_ref/doc/uid/TP30001185-CH203-BAJIBEIF 



regards,

douglas

On Sep 27, 2009, at 7:42 AM, Graham Cox wrote:


Hi again - you got me going now! ;-)

Occurs to me that there's no need to store more than one buffered  
image (actually really obvious once it dawned on me). Checking the  
OpenGL approach, this is what it does also - just one history  
buffered image, which is then drawn into the new image at each  
update, with a lower opacity such that over time it naturally fades  
away. This is much more efficient as there are only two bitblits per  
frame, and a maximum of two images in memory at once and then only  
briefly, no matter how much persistence you dial in or what the  
frame rate is, etc. It also looks a lot more realistic, so it's a  
winner all round. Here's my revised view which still uses NSImage,  
but even with this is working nice and smoothly. I also added a  
target to show how actual blips on the screen could be handled.



@interface GCRadarView : NSView
{
NSTimer*mTimer;
NSTimeInterval  mLastUpdateTime;
CGFloat mAngle;
NSImage*mHistoryImage;
}


- (void)drawHistoryBuffer;
- (void)updateHistoryBuffer;
- (void)drawContentIntoImage:(NSImage*) theImage;
- (void)animateWithTimer:(NSTimer*) timer;

- (IBAction)startSweep:(id) sender;
- (IBAction)stopSweep:(id) sender;

@end


#define SWEEP_RATE  0.5 // 
radians per second


//



#import GCRadarView.h


@implementation GCRadarView

- (void)drawHistoryBuffer
{
// draw the current buffered image to the view

	[mHistoryImage drawInRect:[self bounds] fromRect:NSZeroRect  
operation:NSCompositeSourceOver fraction:1.0];

}


- (void)updateHistoryBuffer
{
	NSImage* newImage = [[NSImage alloc] initWithSize:[self  
bounds].size];


	// copy the current history into it at reduced opacity - dial in  
different opacity values to change the persistence
	// values closer to 1.0 give more persistence, closer to 0 give  
less. 1.0 gives infinite persistence, so the image never fades.


[newImage lockFocus];

if( mHistoryImage )
		[mHistoryImage drawInRect:[self bounds] fromRect:NSZeroRect  
operation:NSCompositeSourceOver fraction:0.92];


// draw new content

[self drawContentIntoImage:newImage];
[newImage unlockFocus];

// this is now the history buffer:

[mHistoryImage release];
mHistoryImage = newImage;
}


- (void)drawContentIntoImage:(NSImage*) theImage
{
// draw view content to the image. Image is already focused.

	NSTimeInterval  currentTime = [NSDate  
timeIntervalSinceReferenceDate];

NSTimeInterval  elapsedTime = currentTime - mLastUpdateTime;
mLastUpdateTime = currentTime;

	// sweep rate is 0.5 rad/sec - so how many radians since we last  
updated?


CGFloat angleIncrement = SWEEP_RATE * elapsedTime;
mAngle += angleIncrement;
mAngle = fmod( mAngle, 2 * pi );

// set the transform to this angle rotated around the centre point

NSPoint centre;

centre.x = NSMidX([self bounds]);
centre.y = NSMidY([self bounds]);

[NSGraphicsContext saveGraphicsState];

NSAffineTransform* transform = [NSAffineTransform transform];
[transform translateXBy:centre.x yBy:centre.y];
[transform rotateByRadians:mAngle];
[transform translateXBy:-centre.x yBy:-centre.y];
[transform concat];

// set a shadow to simulate the backscatter glow

NSShadow* shadow = [[NSShadow alloc] init];
	[shadow setShadowColor:[NSColor colorWithCalibratedRed:0.4 green: 
1.0 blue:0.4 alpha:1.0]];

[shadow setShadowOffset:NSZeroSize];
[shadow setShadowBlurRadius:8.0];
[shadow set];

	// draw the sweep line from centre to edge. The transform is  
rotated so draw at a fixed angle.


[[NSColor greenColor] set];
[NSBezierPath setDefaultLineWidth:1.5];
	[NSBezierPath strokeLineFromPoint:centre  
toPoint:NSMakePoint( NSMaxX([self bounds]), NSMidY([self bounds]))];


	// draw the target on the screen when the beam sweeps across it  
to simulate a blip - here just a square
	// restore first so that effect of rotation is removed - target  
stays at a fixed place.


[NSGraphicsContext restoreGraphicsState];

if( fabs(mAngle)  0.1 

Re: Creating a radar sweep effect

2009-09-28 Thread Uli Kusterer

Am 27.09.2009 um 08:50 schrieb Graham Cox:
I have used this approach to simulate an oscilloscope display and it  
works well in terms of realism, but performance can be an issue.  
You'll probably need to store at least 3 or 4 previous frames to  
get the effect you want - there's no really good way to do it in one  
pass and get realism.


 One way to improve performance would be to use CALayers or CGLayers.  
Have a pool of five previous layers, and reuse the oldest of those for  
the new image. By using layers, you can let the graphics card do the  
merging of the six frames, and the expensive drawing only happens  
once. Play with the layer alpha to have them fade out.


 Haven't tried this, but it's something I'd attempt if I was pressed  
for performance.


Cheers,
-- Uli Kusterer
The Witnesses of TeachText are everywhere...
http://groups.yahoo.com/group/mac-gui-dev/

___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Creating a radar sweep effect

2009-09-27 Thread Graham Cox

Hi John,

The difficulty with this kind of display is simulating the persistence  
of the old cathode-ray tubes in a realistic way. Just drawing a shadow  
is unlikely to work, though it might help get you some way by creating  
the glow caused by scattering.


One possibility is to use OpenGL. It has a history buffer mode (may  
not be called that - I forget exactly) that stores the previous image  
at a diminished brightness and that can be stacked for a series of  
frames, giving a fade or trail effect.


Alternatively you can model persistence yourself by buffering up  
several frames (for example, using a NSBitmapImageRep) and then  
drawing the stack for each frame followed by the latest content. I  
have used this approach to simulate an oscilloscope display and it  
works well in terms of realism, but performance can be an issue.  
You'll probably need to store at least 3 or 4 previous frames to get  
the effect you want - there's no really good way to do it in one pass  
and get realism. Fact is those old tubes literally stored the image in  
the phosphors which naturally faded in their own time after the beam  
passed - to simulate that realistically requires that you model the  
image storage.


--Graham


On 27/09/2009, at 11:19 AM, John Cebasek wrote:


Hi All:

I'm wondering what the best way to create a radar sweep effect is?  
(Like in old war movies?)


___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com


Re: Creating a radar sweep effect

2009-09-27 Thread Graham Cox
John, the code below is similar to my oscilloscope view in principle -  
here though I just use an NSImage to buffer the history, as it's  
simplest, but for performance you might try something more  
sophisticated. Also, when drawing the history, this just uses a linear  
opacity ramp - it might work better with a curve of some sort but I'll  
leave that to you!  Hope it helps,


--Graham


@interface GCRadarView : NSView
{
NSMutableArray* mHistoryBuffer;
NSTimer*mTimer;
NSTimeInterval  mLastUpdateTime;
CGFloat mAngle;
}


- (void)drawHistoryBuffer;
- (void)updateHistoryBuffer;
- (void)drawContentIntoImage:(NSImage*) theImage;
- (void)animateWithTimer:(NSTimer*) timer;

- (IBAction)startSweep:(id) sender;
- (IBAction)stopSweep:(id) sender;

@end



#define MAX_HISTORY_BUFFER_SIZE 6
#define SWEEP_RATE  0.3 // radians per second

//

#import GCRadarView.h


@implementation GCRadarView

- (void)drawHistoryBuffer
{
	// draw the stack of images in the history buffer, each one with a  
different transparency


if([mHistoryBuffer count]  0 )
{
CGFloat opacityIncrement = 1.0 / [mHistoryBuffer count];
NSUInteger  i;
NSImage*image;

for( i = 0; i  [mHistoryBuffer count]; ++i )
{
image = [mHistoryBuffer objectAtIndex:i];   

			[image drawInRect:[self bounds] fromRect:NSZeroRect  
operation:NSCompositeSourceOver fraction:(CGFloat)i * opacityIncrement];

}
}
}


- (void)updateHistoryBuffer
{
	// this generates the images. The image list is limited to a maximum  
- if exceeded images are discarded
	// from the front of the list. New images are added to the end of the  
list.


while([mHistoryBuffer count]  MAX_HISTORY_BUFFER_SIZE )
[mHistoryBuffer removeObjectAtIndex:0];

NSImage* newImage = [[NSImage alloc] initWithSize:[self bounds].size];

[newImage lockFocus];
[self drawContentIntoImage:newImage];
[newImage unlockFocus];

[mHistoryBuffer addObject:newImage];
[newImage release];
}


- (void)drawContentIntoImage:(NSImage*) theImage
{
// draw view content to the image. Image is already focused.

NSTimeInterval  currentTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval  elapsedTime = currentTime - mLastUpdateTime;
mLastUpdateTime = currentTime;

	// sweep rate is SWEEP_RATE rad/sec - so how many radians since we  
last updated?


CGFloat angleIncrement = SWEEP_RATE * elapsedTime;
mAngle += angleIncrement;
mAngle = fmod( mAngle, 2 * pi );// not really needed

// set the transform to this angle rotated around the centre point

NSPoint centre;

centre.x = NSMidX([self bounds]);
centre.y = NSMidY([self bounds]);

[NSGraphicsContext saveGraphicsState];

NSAffineTransform* transform = [NSAffineTransform transform];
[transform translateXBy:centre.x yBy:centre.y];
[transform rotateByRadians:mAngle];
[transform translateXBy:-centre.x yBy:-centre.y];
[transform concat];

	// draw the sweep line from centre to edge. The transform is rotated  
so we simply draw at a fixed angle.
	// add a shadow to simulate the glow of backscatter and help hide the  
discrete nature of the sweep lines


NSShadow* shadow = [[NSShadow alloc] init];
	[shadow setShadowColor:[NSColor colorWithCalibratedRed:0.4 green:1.0  
blue:0.4 alpha:1.0]];

[shadow setShadowOffset:NSZeroSize];
[shadow setShadowBlurRadius:8.0];
[shadow set];

// beam line

[[NSColor greenColor] set];
[NSBezierPath setDefaultLineWidth:1.5];
	[NSBezierPath strokeLineFromPoint:centre toPoint:NSMakePoint( NSMaxX 
([self bounds]), 0 )];


[shadow release];

[NSGraphicsContext restoreGraphicsState];
}


- (void)animateWithTimer:(NSTimer*) timer
{
	// timer callback ends up here. It updates the history buffer and  
marks the display needed.


#pragma unused(timer)

[self updateHistoryBuffer];
[self setNeedsDisplay:YES];
}




- (IBAction)startSweep:(id) sender
{
#pragma unused(sender)

if( mTimer == nil )
{
		mTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/30.0  
target:self selector:@selector(animateWithTimer:) userInfo:nil  
repeats:YES];

mLastUpdateTime = [NSDate 

Re: Creating a radar sweep effect

2009-09-27 Thread Graham Cox

Hi again - you got me going now! ;-)

Occurs to me that there's no need to store more than one buffered  
image (actually really obvious once it dawned on me). Checking the  
OpenGL approach, this is what it does also - just one history  
buffered image, which is then drawn into the new image at each update,  
with a lower opacity such that over time it naturally fades away. This  
is much more efficient as there are only two bitblits per frame, and a  
maximum of two images in memory at once and then only briefly, no  
matter how much persistence you dial in or what the frame rate is,  
etc. It also looks a lot more realistic, so it's a winner all round.  
Here's my revised view which still uses NSImage, but even with this is  
working nice and smoothly. I also added a target to show how actual  
blips on the screen could be handled.



@interface GCRadarView : NSView
{
NSTimer*mTimer;
NSTimeInterval  mLastUpdateTime;
CGFloat mAngle;
NSImage*mHistoryImage;
}


- (void)drawHistoryBuffer;
- (void)updateHistoryBuffer;
- (void)drawContentIntoImage:(NSImage*) theImage;
- (void)animateWithTimer:(NSTimer*) timer;

- (IBAction)startSweep:(id) sender;
- (IBAction)stopSweep:(id) sender;

@end


#define SWEEP_RATE  0.5 // 
radians per second


//



#import GCRadarView.h


@implementation GCRadarView

- (void)drawHistoryBuffer
{
// draw the current buffered image to the view

	[mHistoryImage drawInRect:[self bounds] fromRect:NSZeroRect  
operation:NSCompositeSourceOver fraction:1.0];

}


- (void)updateHistoryBuffer
{
NSImage* newImage = [[NSImage alloc] initWithSize:[self bounds].size];

	// copy the current history into it at reduced opacity - dial in  
different opacity values to change the persistence
	// values closer to 1.0 give more persistence, closer to 0 give less.  
1.0 gives infinite persistence, so the image never fades.


[newImage lockFocus];

if( mHistoryImage )
		[mHistoryImage drawInRect:[self bounds] fromRect:NSZeroRect  
operation:NSCompositeSourceOver fraction:0.92];


// draw new content

[self drawContentIntoImage:newImage];
[newImage unlockFocus];

// this is now the history buffer:

[mHistoryImage release];
mHistoryImage = newImage;
}


- (void)drawContentIntoImage:(NSImage*) theImage
{
// draw view content to the image. Image is already focused.

NSTimeInterval  currentTime = [NSDate timeIntervalSinceReferenceDate];
NSTimeInterval  elapsedTime = currentTime - mLastUpdateTime;
mLastUpdateTime = currentTime;

	// sweep rate is 0.5 rad/sec - so how many radians since we last  
updated?


CGFloat angleIncrement = SWEEP_RATE * elapsedTime;
mAngle += angleIncrement;
mAngle = fmod( mAngle, 2 * pi );

// set the transform to this angle rotated around the centre point

NSPoint centre;

centre.x = NSMidX([self bounds]);
centre.y = NSMidY([self bounds]);

[NSGraphicsContext saveGraphicsState];

NSAffineTransform* transform = [NSAffineTransform transform];
[transform translateXBy:centre.x yBy:centre.y];
[transform rotateByRadians:mAngle];
[transform translateXBy:-centre.x yBy:-centre.y];
[transform concat];

// set a shadow to simulate the backscatter glow

NSShadow* shadow = [[NSShadow alloc] init];
	[shadow setShadowColor:[NSColor colorWithCalibratedRed:0.4 green:1.0  
blue:0.4 alpha:1.0]];

[shadow setShadowOffset:NSZeroSize];
[shadow setShadowBlurRadius:8.0];
[shadow set];

	// draw the sweep line from centre to edge. The transform is rotated  
so draw at a fixed angle.


[[NSColor greenColor] set];
[NSBezierPath setDefaultLineWidth:1.5];
	[NSBezierPath strokeLineFromPoint:centre toPoint:NSMakePoint( NSMaxX 
([self bounds]), NSMidY([self bounds]))];


	// draw the target on the screen when the beam sweeps across it to  
simulate a blip - here just a square
	// restore first so that effect of rotation is removed - target stays  
at a fixed place.


[NSGraphicsContext restoreGraphicsState];

if( fabs(mAngle)  0.1 )
{
		NSBezierPath* target = [NSBezierPath bezierPathWithRect:NSMakeRect 
(( centre.x + NSMaxX([self bounds])) / 2.0, NSMidY([self bounds]), 10,  
10 )];

[[NSColor greenColor] set];
[target fill];
}

[shadow release];
}


- (void)animateWithTimer:(NSTimer*) timer
{
	// timer callback ends up here. It updates the 

Re: Creating a radar sweep effect

2009-09-27 Thread Jon Gilkison
You can do this with a single accumulating bitmap.
1. Create a bitmap the size of your view filled with the background color
2. Fill the bitmap with the background color using an alpha = 1 / number of
steps
3. Draw the radar onto the bitmap
4. Draw the bitmap in the view
5. Go to step 2

(I have done this exact thing on Win32, but not Cocoa so buyer beware).
___

Cocoa-dev mailing list (Cocoa-dev@lists.apple.com)

Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com

Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com

This email sent to arch...@mail-archive.com