views:

793

answers:

4

Hi,

I'm using Quartz-2D for iPhone to display a route on a map. The route is colored according to temperature. Because some streets are colored yellow, I am using a slightly thicker black line under the route line to create a border effect, so that yellow parts of the route are spottable on yellow streets. But, even if the black line is as thick as the route line, the whole route looks like a worm (very ugly). I tought this was because I was drawing lines from waypoint to waypoint, instead using the last waypoint as the next starting waypoint. That way if there is a couple of waypoints missing, the route will still have no cuts.

What do I need to do to display both lines without a worm effect?

-(void) drawRect:(CGRect) rect
{
CSRouteAnnotation* routeAnnotation = (CSRouteAnnotation*)self.routeView.annotation;

// only draw our lines if we're not int he moddie of a transition and we 
// acutally have some points to draw. 
if(!self.hidden && nil != routeAnnotation.points && routeAnnotation.points.count >   0)
{
    CGContextRef context = UIGraphicsGetCurrentContext(); 

    Waypoint* fromWaypoint = [[Waypoint alloc] initWithDictionary:[routeAnnotation.points objectAtIndex:0]];
    Waypoint* toWaypoint;

    for(int idx = 1; idx < routeAnnotation.points.count; idx++)
    {
        toWaypoint = [[Waypoint alloc] initWithDictionary:[routeAnnotation.points objectAtIndex:idx]];


        CLLocation* fromLocation = [fromWaypoint getLocation];
        CGPoint fromPoint = [self.routeView.mapView convertCoordinate:fromLocation.coordinate toPointToView:self];

        CLLocation* toLocation = [toWaypoint getLocation];
        CGPoint toPoint = [self.routeView.mapView convertCoordinate:toLocation.coordinate toPointToView:self];

        routeAnnotation.lineColor = [fromWaypoint.weather getTemperatureColor];

        CGContextBeginPath(context);
        CGContextSetLineWidth(context, 3.0);
        CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
        CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
        CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
        CGContextStrokePath(context);
        CGContextClosePath(context);

        CGContextBeginPath(context);
        CGContextSetLineWidth(context, 3.0);
        CGContextSetStrokeColorWithColor(context,    routeAnnotation.lineColor.CGColor);
        CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
        CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
        CGContextStrokePath(context);
        CGContextClosePath(context);


        fromWaypoint = toWaypoint;
    }

    [fromWaypoint release];
    [toWaypoint release];       
}
}

Also, I get a

<Error>: CGContextClosePath: no current point.

error, which I think is bullshit.

Please hint me! :)


A: 

Sounds like it might be something to do with the line caps. Try drawing with flat end caps and see it that helps.

UPDATE: I see what was happening now. It is simply the "background" line overlapping the pixels covered by the previous "background"+"forground" line draw. Your change to draw all the "background" lines then all the "foreground" lines avoids this issue. Your lines still overdraw some pixels, but only of the same colour so you won't notice. (Note that most of the line end cap styles extend beyound the actual point in the line, making the effect more pronounced - more overlapping pixels.)

Andy J Buchanan
A: 

Instead of drawing two lines, could you just draw one and use the Shadows ability?

slf
A: 

Thanks guys! So, simply adding a shadow or the line caps didn't help, the effect stayed the same. However, I just played with the code a little and it turns out that if I draw both lines in full path separately (in two for loops), the effect is gone! Then I added square line caps to the background line to make it slightly nicer.

Now the only thing I'm wondering about is...what's the explanation for this? Here's the new code, I'll optimize it later...

-(void) drawRect:(CGRect) rect {
CSRouteAnnotation* routeAnnotation = (CSRouteAnnotation*)self.routeView.annotation;

// only draw our lines if we're not int he moddie of a transition and we 
// acutally have some points to draw. 
if(!self.hidden && nil != routeAnnotation.points && routeAnnotation.points.count > 0)
{
    CGContextRef context = UIGraphicsGetCurrentContext(); 


    Waypoint* fromWaypoint = [[Waypoint alloc] initWithDictionary:[routeAnnotation.points objectAtIndex:0]];
    Waypoint* toWaypoint;

    for(int idx = 1; idx < routeAnnotation.points.count; idx++)
    {
        toWaypoint = [[Waypoint alloc] initWithDictionary:[routeAnnotation.points objectAtIndex:idx]];


        CLLocation* fromLocation = [fromWaypoint getLocation];
        CGPoint fromPoint = [self.routeView.mapView convertCoordinate:fromLocation.coordinate toPointToView:self];

        CLLocation* toLocation = [toWaypoint getLocation];
        CGPoint toPoint = [self.routeView.mapView convertCoordinate:toLocation.coordinate toPointToView:self];

        routeAnnotation.lineColor = [fromWaypoint.weather getTemperatureColor];

        CGContextBeginPath(context);
        CGContextSetLineWidth(context, 3.5);
        CGContextSetStrokeColorWithColor(context, [UIColor blackColor].CGColor);
        CGContextSetLineCap(context, kCGLineCapSquare);
        CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
        CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
        CGContextStrokePath(context);
        CGContextClosePath(context);

        fromWaypoint = toWaypoint;

    }

    // zweite for schleife
    for(int idx = 1; idx < routeAnnotation.points.count; idx++)
    {
        toWaypoint = [[Waypoint alloc] initWithDictionary:[routeAnnotation.points objectAtIndex:idx]];


        CLLocation* fromLocation = [fromWaypoint getLocation];
        CGPoint fromPoint = [self.routeView.mapView convertCoordinate:fromLocation.coordinate toPointToView:self];

        CLLocation* toLocation = [toWaypoint getLocation];
        CGPoint toPoint = [self.routeView.mapView convertCoordinate:toLocation.coordinate toPointToView:self];

        routeAnnotation.lineColor = [fromWaypoint.weather getTemperatureColor];

        CGContextBeginPath(context);

        CGContextSetLineWidth(context, 3.0);
        CGContextSetStrokeColorWithColor(context, routeAnnotation.lineColor.CGColor);
        CGContextSetLineCap(context, kCGLineCapSquare );
        CGContextMoveToPoint(context, fromPoint.x, fromPoint.y);
        CGContextAddLineToPoint(context, toPoint.x, toPoint.y);
        CGContextStrokePath(context);
        CGContextClosePath(context);

    }

    [fromWaypoint release];
   }
}       
Leonard
A: 

Also, I get a

<Error>: CGContextClosePath: no current point.

Stroking the path end the current path context.

Andy J Buchanan