【问题标题】:Drawing an Arrow with NSBezierPath between two Points在两点之间使用 NSBezierPath 绘制箭头
【发布时间】:2013-01-08 03:25:52
【问题描述】:

所以我正在尝试生成一个NSBezierPath,它看起来像两点之间的箭头,它可以位于视图上的任何位置,因此 startPoint 可以大于或小于端点。

当用户像在绘图应用中一样拖动鼠标时,箭头会更新。

我已经想通了,我可能必须使用变换和一些数学来做三角函数,并提出了这个实现:

 +(NSBezierPath *)arrowWithStart:(NSPoint)startPoint andEnd:(NSPoint)endPoint{
        NSBezierPath* path = [NSBezierPath bezierPath];

        CGFloat width = endPoint.x - startPoint.x;
        CGFloat height = endPoint.y - startPoint.y;
        CGFloat angle = atan2(width, height);

        NSAffineTransform *tr = [NSAffineTransform transform];
        [tr translateXBy:startPoint.x yBy:startPoint.y];
        [tr scaleXBy:width yBy:height];
        [tr rotateByDegrees:angle];

        [path moveToPoint:CGPointZero];
        [path lineToPoint:CGPointMake(0.75, 0.7)];
        [path lineToPoint:CGPointMake(0.8, 0.65)];
        [path lineToPoint:CGPointMake(1, 1)];
        [path lineToPoint:CGPointMake(0.65, 0.8)];
        [path lineToPoint:CGPointMake(0.7, 0.75)];
        [path closePath];

        [path transformUsingAffineTransform:tr];

        return path;
    }

当点是某种对角线时,此代码会生成漂亮的箭头, 喜欢

  • (0,0)
  • (-2,-2)

彼此,但当点越来越接近水平或垂直线时,例如

  • (2,3)
  • (5,3)

结果变成一条没有箭头的直线。

所以我认为我在转换矩阵中做错了什么。

如果有人知道我在哪里犯了错误,那就太好了。

【问题讨论】:

    标签: objective-c macos drawing geometry


    【解决方案1】:

    您需要一个仿射变换,将点(0, 0) 转换为startPoint 和将(1, 1) 转换为endPoint。这种转换可以直接计算:

    CGFloat tx = startPoint.x;
    CGFloat ty = startPoint.y;
    CGFloat a = ((endPoint.x - startPoint.x) + (endPoint.y - startPoint.y))/2.;
    CGFloat b = (-(endPoint.x - startPoint.x) + (endPoint.y - startPoint.y))/2.;
    NSAffineTransformStruct transformStruct = { a, b, -b, a, tx, ty };
    NSAffineTransform *tr = [NSAffineTransform transform];
    [tr setTransformStruct:transformStruct];
    

    解释:

    NSAffineTransformStruct transformStruct = { a, b, -b, a, tx, ty };
    

    描述了平移、缩放和旋转的一般组合,即没有剪切的仿射变换。要求(0, 0) -> startPoint,(1, 1) -> endPoint给出方程

    startPoint.x = 0 * a + 0 * (-b) + tx
    startPoint.y = 0 * b + 0 *   a  + ty
    endPoint.x   = 1 * a + 1 * (-b) + tx
    endPoint.y   = 1 * b + 1 *   a  + tx
    

    并为abtxty 求解这些方程给出了上述解。 (有关更多信息,请参阅“可可绘图指南”中的Transform Mathematics。)

    您的原始代码的问题在于

    • atan2y 作为第一个参数,因此 atan2(height, width) 将计算角度。
    • 对于水平或垂直线,widthheight,因此一个比例因子为零,这会导致直线没有箭头。

    【讨论】:

    • 第一个版本的公式有一个符号错误,我现在已经修复了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多