2016-08-18 59 views
7

我能夠使用任意選定的字體和大小生成UIBezierPath字符。現在我想在貝塞爾路徑之間製作一條蝕刻線。我可以得到貝塞爾路徑的中心點嗎?或者我可以用任何其他方式讓中心虛線和遵循該路徑?獲取UIBezier路徑的中心點

這裏是我的代碼是如何做到這一點

Reference Link. I want something like this.

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

+0

http://stackoverflow.com/a/31698463/988769 – Kreiri

+0

增加lineWidth值及其不工作。我有一個彎曲的路徑爲不同的字母。我也想畫出路徑,而不是輪廓。 – NiKKi

+0

你試過這個嗎https://stackoverflow.com/questions/34693651/how-to-draw-line-on-image-pattern-exactly/34723668#34723668? –

回答

2

雖然貝塞爾路徑是簡單的畫圖一個方便的選擇,他們是複雜的計算,所以這將是過於昂貴和複雜的使用它們的目的。這是因爲您需要能夠計算路徑上的任意點並知道前一點以便了解當前的方向。

您需要對字符進行一些其他描述,以便您更輕鬆地瞭解這些詳細信息。這意味着使用字體的簡單矢量(或筆畫)描述(如註釋中的rob mayoff所述)。這些描述將字符分解成許多易於操作的直線段。它們全都受y=mx+c計算的控制,並且每條線段上始終知道2個點,因此很容易在它們之間進行插值並瞭解運動的方向。

如果rob提供的鏈接上的描述(here)對於要顯示字符的大小不夠「準確」,則可以使用更多的點創建新版本,以便實現更接近貝塞爾曲線選項。現在

,這個說明你有很多選擇......

對於拖動手指沿着你可以點之間插入的路徑來尋找路徑上的最近點到當前觸摸點和確定何時接觸點偏離路徑太遠,或者與路徑相交。這種相交處理也是您如何確定覆蓋率的百分比。你只需要選擇插值間隙距離(選擇合適的分辨率而不會產生太多真正靠近的點),並且可以容忍觸點可以距「下一個」路徑點多遠。

這還允許您鏈接的視頻中的其他內容,例如沿着(內插)路徑的每個點拖放圖像併爲這些圖像製作動畫效果。

3

我可以得到bezier路徑的中心點嗎?或者其他方式 ,我可以使中心虛線和遵循該路徑?

要知道,用戶的手指沿着路徑去與否,你必須HIT-檢測在路徑上

要確定觸摸事件是否發生在 路徑的填充部分上,可以使用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; 
} 

檢查此鏈接瞭解更多有關Hit-Detection on a Path

獲取路徑的中心

你可以得到路的寬度爲myPath.bounds.size.width;,並獲得路徑的中心僅通過劃分寬度2。

並提請虛線檢查這個answer

爲了使虛線上的任何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]; 
+0

我沒有使用這種方法, – NiKKi

+0

嘗試使用'CGPathContainsPoint(path,NULL,point,NO);'而不是'CGContextPathContainsPoint(context,point,mode);' –

+0

要繪製一條虛線,從開始到結束點。我的角色是彎曲的。 – NiKKi

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; 
+0

如果你看過這個問題,問題是在UIBezierpath的中心繪製虛線。 –

2

您可以沿着UIBezierPath計算積分與這個開源回購代碼:

https://github.com/ImJCabus/UIBezierPath-Length

如果您在「一」字表示爲貝塞爾路徑,你可以計算出紅色點在上面的圖像寫如下:

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 
} 
+0

這就是要點。不是中心點。 – NiKKi

+0

如果你的輸入是來自'CTFontCreatePathForGlyph'的字形的輪廓,並且你想要一個算法輸出一個代表如何繪製字形的路徑,這將是非常具有挑戰性的(如果可能的話)使它工作100%正確。您的算法可能需要解釋很多古怪的字形,因此在分析輸入時幾乎不可能做出任何假設。在你鏈接到的視頻中,我猜測他們從中心路徑開始,並使用該路徑以特定寬度繪製角色,而不是使用輪廓。 – BradB

0

你想要的是相當複雜,但我相信它可以實現通過以下步驟:

1)用你的方法得到字母輪廓路徑

2)創建使用CGPathCreateCopyByStrokingPath了一條新路與lineWidth等於1

3)get all segments of the new path

4)find all intersection points of all segments

5)確定哪些相交線相鄰並使用它們的交點來形成中心線

6)重複步驟2-6,在步驟2