【问题标题】:Drawing triangle/arrow on a line with CGContext使用 CGContext 在一条线上绘制三角形/箭头
【发布时间】:2011-01-30 19:23:33
【问题描述】:

我正在使用 route-me 的框架来处理位置。 在此代码中,两个标记(点)之间的路径将绘制为一条线。

我的问题:“如果我想在线的中间(或顶部)添加一个箭头,我应该添加什么代码,以便它指向方向”

谢谢



- (void)drawInContext:(CGContextRef)theContext
{
    renderedScale = [contents metersPerPixel];

    float scale = 1.0f / [contents metersPerPixel];

    float scaledLineWidth = lineWidth;
    if(!scaleLineWidth) {
        scaledLineWidth *= renderedScale;
    }
    //NSLog(@"line width = %f, content scale = %f", scaledLineWidth, renderedScale);

    CGContextScaleCTM(theContext, scale, scale);

    CGContextBeginPath(theContext);
    CGContextAddPath(theContext, path);

    CGContextSetLineWidth(theContext, scaledLineWidth);
    CGContextSetStrokeColorWithColor(theContext, [lineColor CGColor]);
    CGContextSetFillColorWithColor(theContext, [fillColor CGColor]);

    // according to Apple's documentation, DrawPath closes the path if it's a filled style, so a call to ClosePath isn't necessary
    CGContextDrawPath(theContext, drawingMode);
}

【问题讨论】:

  • 我不久前得到了codeguru.com/cpp/g-m/gdi/article.php/c3683 无论如何谢谢你的答案 Greetz
  • Pete,您最好还是将答案标记为已接受,或者将您的答案作为答案发布然后接受。
  • @Pete 你为什么不标记正确的答案(我的意思是 Friedhelm 的)?

标签: iphone core-graphics quartz-2d cgcontext


【解决方案1】:
- (void) drawLine: (CGContextRef) context from: (CGPoint) from to: (CGPoint) to 
{
    double slopy, cosy, siny;
    // Arrow size
    double length = 10.0;  
    double width = 5.0;

    slopy = atan2((from.y - to.y), (from.x - to.x));
    cosy = cos(slopy);
    siny = sin(slopy);

    //draw a line between the 2 endpoint
    CGContextMoveToPoint(context, from.x - length * cosy, from.y - length * siny );
    CGContextAddLineToPoint(context, to.x + length * cosy, to.y + length * siny);
    //paints a line along the current path
    CGContextStrokePath(context);

    //here is the tough part - actually drawing the arrows
    //a total of 6 lines drawn to make the arrow shape
    CGContextMoveToPoint(context, from.x, from.y);
    CGContextAddLineToPoint(context,
                        from.x + ( - length * cosy - ( width / 2.0 * siny )),
                        from.y + ( - length * siny + ( width / 2.0 * cosy )));
    CGContextAddLineToPoint(context,
                        from.x + (- length * cosy + ( width / 2.0 * siny )),
                        from.y - (width / 2.0 * cosy + length * siny ) );
    CGContextClosePath(context);
    CGContextStrokePath(context);

    /*/-------------similarly the the other end-------------/*/
    CGContextMoveToPoint(context, to.x, to.y);
    CGContextAddLineToPoint(context,
                        to.x +  (length * cosy - ( width / 2.0 * siny )),
                        to.y +  (length * siny + ( width / 2.0 * cosy )) );
    CGContextAddLineToPoint(context,
                        to.x +  (length * cosy + width / 2.0 * siny),
                        to.y -  (width / 2.0 * cosy - length * siny) );
    CGContextClosePath(context);
    CGContextStrokePath(context);
}

【讨论】:

    【解决方案2】:

    一旦路径上有两个点,实际三角形/箭头的绘制就很容易了。

    CGContextMoveToPoint( context , ax , ay );
    CGContextAddLineToPoint( context , bx , by );
    CGContextAddLineToPoint( context , cx , cy );
    CGContextClosePath( context ); // for triangle
    

    获得积分有点棘手。你说路径是一条线,而不是一条曲线或一系列曲线。这样更容易。

    使用 CGPathApply 选择路径上的两个点。可能这是最后两个点,其中一个可能是 kCGPathElementMoveToPoint,另一个可能是 kCGPathElementAddLineToPoint。设 mx,my 为第一个点,nx,ny 为第二个点,所以箭头将从 m 指向 n。

    假设您希望箭头位于直线的末端,bx,by 从上方将等于直线上的 nx,ny。在 mx,my 和 nx,ny 之间选择一个点 dx,dy 来计算其他点。

    现在计算 ax,ay 和 cx,cy 使得它们与 dx,dy 在一条线上并且与路径等距。以下应该是接近的,虽然我可能得到了一些错误的迹象:

    r = atan2( ny - my , nx - mx );
    bx = nx;
    by = ny;
    dx = bx + sin( r ) * length;
    dy = by + cos( r ) * length;
    r += M_PI_2; // perpendicular to path
    ax = dx + sin( r ) * width;
    ay = dy + cos( r ) * width;
    cx = dx - sin( r ) * width;
    cy = dy - cos( r ) * width;
    

    长度是箭尖到基部的距离,宽度是箭杆到倒钩的距离,也就是箭头宽度的一半。

    如果path是一条曲线,那么不是找mx,my作为前一个点或者move,而是最终曲线的最终控制点。每个控制点都在一条与曲线相切并通过相邻点的线上。

    【讨论】:

      【解决方案3】:

      我发现了这个问题,因为我有同样的问题。我拿了drawonward的例子,它是如此接近......但是通过翻转cos和sin,我能够让它工作:

      r = atan2( ny - my , nx - mx );
      r += M_PI;
      bx = nx;
      by = ny;
      dx = bx + cos( r ) * length;
      dy = by + sin( r ) * length;
      r += M_PI_2; // perpendicular to path
      ax = dx + cos( r ) * width;
      ay = dy + sin( r ) * width;
      cx = dx - cos( r ) * width;
      cy = dy - sin( r ) * width;
      

      一旦我这样做了,我的箭头指向完全错误的方向。所以我添加了第二行 (r += M_PI;)

      感谢drawonward!

      【讨论】:

        【解决方案4】:

        这里是 Friedhelm Brügge 的 Swift 4+ 版本回答:(我会在图片上画出来)

        func drawArrow(image: UIImage, ptSrc: CGPoint, ptDest: CGPoint) {
        
                // create context with image size
                UIGraphicsBeginImageContext(image.size)
                let context = UIGraphicsGetCurrentContext()
        
                // draw current image to the context
                image.draw(in: CGRect(x: 0, y: 0, width: image.size.width, height: image.size.height))
        
                var slopY: CGFloat, cosY: CGFloat, sinY: CGFloat;
                // Arrow size
                let length: CGFloat = 35.0;
                let width: CGFloat = 35.0;
        
                slopY = atan2((ptSrc.y - ptDest.y), (ptSrc.x - ptDest.x));
                cosY = cos(slopY);
                sinY = sin(slopY);
        
                //here is the tough part - actually drawing the arrows
                //a total of 6 lines drawn to make the arrow shape
                context?.setFillColor(UIColor.white.cgColor)
                context?.move(to: CGPoint(x: ptSrc.x, y: ptSrc.y))
                context?.addLine(to: CGPoint(x: ptSrc.x + ( -length * cosY - ( width / 2.0 * sinY )), y: ptSrc.y + ( -length * sinY + ( width / 2.0 * cosY ))))
                context?.addLine(to: CGPoint(x: ptSrc.x + (-length * cosY + ( width / 2.0 * sinY )), y: ptSrc.y - (width / 2.0 * cosY + length * sinY )))
                context?.closePath()
                context?.fillPath()
        
                context?.move(to: CGPoint(x: ptSrc.x, y: ptSrc.y))
                context?.addLine(to: CGPoint(x: ptDest.x +  (length * cosY - ( width / 2.0 * sinY )), y: ptDest.y +  (length * sinY + ( width / 2.0 * cosY ))))
                context?.addLine(to: CGPoint(x: ptDest.x +  (length * cosY + width / 2.0 * sinY), y: ptDest.y -  (width / 2.0 * cosY - length * sinY)))
                context?.closePath()
                context?.fillPath()
        
                // draw current context to image view
                imgView.image = UIGraphicsGetImageFromCurrentImageContext()
        
                //close context
                UIGraphicsEndImageContext()
            }
        

        【讨论】:

          猜你喜欢
          • 2015-04-09
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-04-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多