获取UIBezierpath的中心点

10
我可以生成任意选定字体和大小的字符的UIBezierPath。现在我想在bezier路径之间制作蚀刻线。我能得到贝塞尔路径沿着的中心点吗?或者有其他方法可以制作中心虚线并跟随该路径吗?
以下是我的代码: 参考链接。我想要类似这样的效果。
 UIBezierPath *path = [UIBezierPath bezierPathWithRoundedRect:CGRectMake(0, 0, 568, 568) cornerRadius:0];
UIBezierPath *circlePath = [self createArcPath];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];





shapeView = [CAShapeLayer layer];
shapeView.geometryFlipped = false;
shapeView.path = path.CGPath;
shapeView.fillRule = kCAFillRuleEvenOdd;
shapeView.fillColor = [UIColor grayColor].CGColor;
shapeView.opacity = 1.0;
shapeView.lineDashPattern = @[@2, @3];
[self.view.layer addSublayer:shapeView];

CGFloat dashes[] = {2, 3};
[path setLineDash:dashes count:2 phase:0];


- (UIBezierPath *)createArcPath
{
// Create path from text
// See: http://www.codeproject.com/KB/iPhone/Glyph.aspx
// License: The Code Project Open License (CPOL) 1.02 http://www.codeproject.com/info/cpol10.aspx
letters = CGPathCreateMutable();

CTFontRef font = CTFontCreateWithName(CFSTR("Helvetica-Bold"),80, NULL);
NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:
                       (__bridge id)font, kCTFontAttributeName,//د
                       nil];//ج
NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:@"H"
                                                                 attributes:attrs];
CTLineRef line = CTLineCreateWithAttributedString((CFAttributedStringRef)attrString);
CFArrayRef runArray = CTLineGetGlyphRuns(line);

// for each RUN
for (CFIndex runIndex = 0; runIndex < CFArrayGetCount(runArray); runIndex++)
{
    // Get FONT for this run
    CTRunRef run = (CTRunRef)CFArrayGetValueAtIndex(runArray, runIndex);
    CTFontRef runFont = CFDictionaryGetValue(CTRunGetAttributes(run), kCTFontAttributeName);

    // for each GLYPH in run
    for (CFIndex runGlyphIndex = 0; runGlyphIndex < CTRunGetGlyphCount(run); runGlyphIndex++)
    {
        // get Glyph & Glyph-data
        CFRange thisGlyphRange = CFRangeMake(runGlyphIndex, 1);
        CGGlyph glyph;
        CGPoint position;
        CTRunGetGlyphs(run, thisGlyphRange, &glyph);
        CTRunGetPositions(run, thisGlyphRange, &position);

        // Get PATH of outline
        {
            CGPathRef letter = CTFontCreatePathForGlyph(runFont, glyph, NULL);
            CGAffineTransform t = CGAffineTransformMakeTranslation(position.x+200, position.y+80);
            CGPathAddPath(letters, &t, letter);
            CGPathRelease(letter);
        }
    }
}
CFRelease(line);

self.path = [UIBezierPath bezierPath];
[self.path appendPath:[UIBezierPath bezierPathWithCGPath:letters]];

return self.path;


}

The center dots points I want to draw which is in the cenyter of the bezierPath


https://dev59.com/7F8e5IYBdhLWcg3wLX0-#31698463 - Kreiri
你尝试过这个吗 https://dev59.com/epLea4cB1Zd3GeqP7djb#34723668? - Teja Nandamuri
1
你的路径是否勾勒出图像中的白色区域?还是你的路径沿着白色区域的中心运行? - rob mayoff
2
你所要求的并没有简单的方法。也许你应该考虑使用笔画字体,也称为雕刻字体Hershey Simplex是最容易获得的。 - rob mayoff
@robmayoff - 有没有办法让我可以在文本上绘制颜色,并且知道绘制了多大的区域和剩下多少。另外,我想指示绘制的方向。我想要类似这样的效果:https://www.youtube.com/watch?v=LxS1vq8h35g - NiKKi
显示剩余6条评论
5个回答

3
我能得到贝塞尔路径的中心点吗?或者有其他方法可以使中心点成为虚线并沿着该路径移动?
要知道用户的手指是否沿着路径移动,您需要在路径上进行“命中检测”。
要确定触摸事件是否发生在路径的填充部分上,可以使用UIBezierPath的containsPoint:方法。该方法针对路径对象中的所有封闭子路径测试指定的点,并在它位于任何这些子路径上或内部时返回YES。
如果您想在路径的描边部分(而不是填充区域)上执行命中测试,则必须使用Core Graphics。CGContextPathContainsPoint函数让您测试当前分配给图形上下文的路径的填充或描边部分上的点。
以下方法测试指定点是否与指定路径相交。 inFill参数允许调用者指定是否应针对路径的填充或描边部分进行测试。调用者传递的路径必须包含一个或多个封闭子路径,以使命中检测成功。
测试点与路径对象的交点。
- (BOOL)containsPoint:(CGPoint)point onPath:(UIBezierPath *)path inFillArea:(BOOL)inFill
{
   CGContextRef context = UIGraphicsGetCurrentContext();
   CGPathRef cgPath = path.CGPath;
   BOOL    isHit = NO;

   // Determine the drawing mode to use. Default to
   // detecting hits on the stroked portion of the path.
   CGPathDrawingMode mode = kCGPathStroke;
   if (inFill)
   {
      // Look for hits in the fill area of the path instead.
      if (path.usesEvenOddFillRule)
         mode = kCGPathEOFill;
      else
         mode = kCGPathFill;
   }

   // Save the graphics state so that the path can be removed later.
   CGContextSaveGState(context);
   CGContextAddPath(context, cgPath);

   // Do the hit detection.
   isHit = CGContextPathContainsPoint(context, point, mode);

   CGContextRestoreGState(context);

   return isHit;
}

请查看此链接了解有关路径上的命中检测的更多信息。

获取路径中心

您可以使用myPath.bounds.size.width;获取路径的宽度,要获取路径中心只需将宽度除以2。

要绘制虚线,请查看答案

要在任何UIBezierPath上绘制虚线,例如:

CGFloat dashes[] = {2, 3};
//passing an array with the values {2,3} sets a dash pattern that alternates between a 2 space-unit-long painted segment and a 3 space-unit-long unpainted segment.
UIBezierPath *path = [UIBezierPath bezierPath];
[path setLineDash:dashes count:2 phase:0];

要在 CAShapeLayer 上使用虚线,可以使用属性 lineDashPattern,如下:

shapeView.lineDashPattern = @[@2, @3];

我使用这种方法没有被击中。 - NiKKi
尝试使用 CGPathContainsPoint(path, NULL, point, NO); 替代 CGContextPathContainsPoint(context, point, mode); - Sunil Sharma
要绘制虚线,您需要从起点到终点连接绘制。我的字符是弯曲的。 - NiKKi
我已经更新了答案,展示如何向任何 UIBezierPathCAShapeLayer 添加虚线。 - Sunil Sharma
嘿,我已经按照你的要求更新了代码,但是虚线还是没有出现。我已经在上面更新了代码。 - NiKKi
显示剩余2条评论

2
贝塞尔路径虽然是简单绘图的方便选项,但它们是复杂的计算,因此在这个目的上使用它们将会是代价高昂和复杂的。这是因为你需要能够计算路径上任意点,并知道前一个点以便知道当前方向。
你需要一些其他的字符描述来更容易地了解这些细节。这意味着使用字体的简单矢量(或笔画)描述(如评论中所提到的rob mayoff)。这个描述把字符分解成一系列容易处理的直线段。它们都由一个的计算控制,你总是知道每条线段上的两个点,所以很容易在它们之间插值并知道移动的方向。
如果rob提供的链接中的描述对你想要显示字符的大小不够“准确”,你可以创建新版本,增加更多的点,以实现更接近贝塞尔曲线选项的近似。
现在,有了这个描述,你有很多选择...
对于沿着路径拖动手指,您可以在点之间插值以找到最接近当前触摸点的路径上的点,并确定触摸点何时偏离了路径或与其相交。这种相交处理也是您可以确定覆盖百分比的方式。您只需要选择插值间隔距离(选择适当的分辨率而不会创建太多真正靠在一起的点)和触摸点可以离“下一个”路径点多远的容差。
这还允许进行视频中链接的其他操作,例如在(插值)路径上的每个点处放置图像并围绕这些图像进行动画处理。

2
你可以使用这个开源仓库中的代码计算沿着UIBezierPath的点: https://github.com/ImJCabus/UIBezierPath-Length 如果你已经将你的'a'字符表示为一个贝塞尔路径,你可以编写如下代码来计算上图中的红色点:
UIBezierPath *path = /* ... */;
NSUInteger subdivisions = 100;//however precise you want to be
for(NSUInteger i = 0; i < subdivisions; i++) {
    CGFloat percent = (CGFloat)i/subdivisions;
    CGPoint point = [path pointAtPercentOfLength:percent];
    //draw a dot at this point, or trace it, or whatever you want to do
}

这是轮廓点,而不是中心点。 - NiKKi
如果你的输入是CTFontCreatePathForGlyph函数返回的字形轮廓,并且你想要一个算法输出代表如何绘制该字形的路径,这将非常具有挑战性(如果可能的话)。有很多古怪的字形需要你的算法进行解释,因此分析输入时几乎无法做出任何假设。在你链接的视频中,我猜他们从中间路径开始,在特定宽度上使用该路径绘制字符,而不是使用轮廓。 - BradB

0

你想要的东西相当复杂,但我相信可以通过以下步骤实现:

1)使用您的方法获取字母轮廓路径

2)使用CGPathCreateCopyByStrokingPath创建一个新路径,其中lineWidth等于1

3)获取新路径的所有线段

4)找到所有线段的交点

5)确定哪些相交线是相邻的,并使用它们的交点形成中心线

6)重复步骤2-6,在步骤2中增加lineWidth


0

尝试使用以下代码绘制红色点线:

CAShapeLayer* dotLayer   = [CAShapeLayer layer];
dotLayer.path            = path.CGPath;
dotLayer.strokeColor     = [UIColor redColor].CGColor;
dotLayer.lineWidth       = 2;//or the diameter of the dots
dotLayer.lineDashPattern = @[@0, @10];//change 10 to the distance between dots
dotLayer.lineJoin        = kCALineJoinRound;
dotLayer.lineCap         = kCALineCapRound;

如果您阅读了问题,问题是在UIBezierpath的中心绘制虚线。 - Muhammad Zeeshan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接