2012-12-28 60 views
1

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

用户在绘图应用程序中拖动鼠标时会更新箭头。

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

+(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)

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

所以我认为我在转换矩阵中做了错误的事情。

如果有人知道我犯了什么错误,那会很好。

回答

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的“可可绘画指南”的。)

与原代码的问题是,

  • atan2需要y作为第一个参数,所以atan2(height, width)将计算的角度。
  • 对于水平或垂直线条,widthheight,因此一个缩放因子为零,这会导致没有箭头的直线。
+0

公式的第一个版本中出现了一个符号错误,我现在已经修复了这个错误。 –

+0

编辑:你在这里比我快,再次感谢! – miradorn

相关问题