gpt4 book ai didi

ios - 如何使用Swift/iOS为人类笔画制作动画?

转载 作者:行者123 更新时间:2023-12-02 07:08:47 24 4
gpt4 key购买 nike

目标

我正在尝试使用从字形生成的UIBezierPath创建逼真的人类文字动画。我了解并且已经阅读了许多UIBezierPath问题,这些问题听起来与我的相似(但并不相同)。我的目标是创建一种动画,该动画近似执行字符和字母书写的人类的外观。

背景

我创建了一个游乐场,以便更好地了解用于对字形进行动画处理的路径,就好像它们是手工绘制的一样。

Apple CAShapeLayer中的几个概念(strokeStart和strokeEnd)在制作动画时似乎并没有达到预期的效果。我认为一般人会认为笔触就好像是用书写工具(基本上是直线或曲线)完成的一样。我们认为笔划和填充线是一条线,因为我们的书写工具无法区分笔划和填充。

但是,当设置动画时,路径的轮廓由线段构成(填充被单独处理,并且不清楚如何为填充位置设置动画吗?)。我要实现的是自然的人为笔迹/曲线,它显示了笔画的开始和结束以及随着动画从头到尾的移动而添加的填充部分。最初看起来很简单,但我认为可能需要对填充位置进行动画处理(不确定如何执行此操作),笔画的开始/结束(不确定是否需要这样做,因为上述动画的执行方式有意料之外的警告),并加以利用子路径(如何从已知路径进行重构)。

方法1

因此,我考虑了路径(CGPath/UIBezierPath)的概念。每个路径实际上都包含构造字形所需的所有子路径,因此也许可以重复使用这些子路径并使用CAKeyframeAnimation/CABasicAnimations和动画组来显示部分构造的子路径将是一个不错的方法(尽管每个子路径的填充位置和笔触仍会需要从头到尾进行动画处理?)。

这种方法导致了一个改进的问题:

如果拥有完整的UIBezierPath/CGPath,如何访问和创建UIBezierPath/CGPath(子路径)?

如何使用路径/子路径信息为填充和笔划设置动画,就像使用书写工具绘制的那样? (似乎这意味着需要同时为CALayer的strokeStart/strokeEnd,位置和路径属性设置动画)

注意:

正如人们在代码中可以看到的那样,我确实有从字形获得的完成路径。我可以看到,路径描述为我提供了类似路径的信息。人们将如何获取这些信息并将其重铸为一系列可写笔画的子路径?

(这里的想法是将点信息转换为类似于人的笔触的新数据类型。这意味着需要一种算法来识别每个填充的起点,斜率,终点和边界)

提示

我在Pleco(一个成功实现类似算法的iOS应用)中注意到,每个笔划均由描述人类可写笔划的闭合路径组成。 UIBezierPath具有基于连续连接的填充的闭合路径。需要一种算法来优化重叠填充,以为每个stroke-type创建不同的闭合路径。

埃里卡·萨顿(Erica Sadun)在github上有一组path utilities。我还没有完全研究过这些文件,但是它们可能对确定离散笔划很有用。

UIBezierPath结构似乎基于连续线段/曲线的概念。在填充的相交处出现汇合点,这些汇合点表示方向路径的变化。可以计算一条曲线/线段的笔触/填充角度,并在其他曲线/线中搜索相应的汇合点吗? (即,将线段连接到相交填充的间隙以产生两条单独的路径-假设一条线拾取了点并使用新的线段/曲线重新创建了路径)

内省(introspection):有没有更简单的方法?我是否缺少解决此问题的关键API,书籍或更好的方法?

一些替代方法(无用-需要加载gif或flash)以产生所需的结果:

Good Example (using Flash),带有表示笔划进度的表示层。 (如果可能的话,这就是我想要在Swift/iOS中近似的值)-(alt link-参见左侧的动画图像)

A less good example显示使用渐进路径和填充来近似笔画特征(动画不流畅,需要外部资源):

A Flash version-我对创建Flash动画很熟悉,但是我不希望在1000年代实现这些动画(尽管我可能还可以转换算法以利用带有CSS动画的HTML5 Canvas ,但我不太愿意在iOS上实现这些动画)。但是这种思路似乎有点遥远,毕竟,我想要的路径信息存储在我从提供的字体/字符串中提取的字形中。

方法2

我正在考虑使用stroke-based字体而不是outline-based字体来获取正确的路径信息(即一种将填充表示为路径的信息)。如果成功,此方法将比近似笔划,笔划类型,交点和笔划顺序更干净。我已经向苹果提交了一份雷达,建议将基于笔触的字体添加到iOS(#20426819)。尽管进行了这些努力,但我仍然没有放弃形成一种算法,该算法可以根据贝塞尔曲线路径上的线段和曲线来解析部分笔划,完整笔划,相交和汇合点。

根据讨论/答案更新思想

根据以下任何正在进行的对话和答案提供以下附加信息。

笔划顺序很重要,大多数语言(在这种情况下为中文)都明确定义了stroke typesstroke order rules,它们似乎提供了一种机制,可以根据每个CGPathElement提供的点信息来确定类型和顺序。

CGPathApply和CGPathApplierFunction看起来很有希望作为枚举子路径的一种方法(保存到数组并应用填充动画)

可以将掩模应​​用于该层以露出子层的一部分
(我以前没有使用过此属性,但是看来是否可以在子路径上移动一个可以帮助动画填充的 mask 层?)

每个路径定义了大量的点。好像BezierPath是仅使用字形的轮廓定义的。这一事实使了解交叉填充的开始,结束和并集成为消除特定填充歧义的重要因素。

可以使用其他external libraries,以便更好地解决笔划行为。其他技术,例如Saffron Type System或其派生词之一,也可以应用于此问题域。

最简单的仅对笔触进行动画处理的解决方案的一个基本问题是,可用的iOS字体是轮廓字体,而不是基于笔触的字体。一些商业制造商确实生产基于笔触的字体。如果您要测试其中的一种,请随时使用link to the playground file

我认为这是一个普遍的问题,在寻求解决方案时,我将继续更新帖子。如果需要进一步的信息,或者我可能缺少某些必要的概念,请在评论中让我知道。

可能的解决方案

我一直在寻找最简单的解决方案。问题源于字体的结构是轮廓字体,而不是基于笔划的字体。我找到了一个基于笔触的字体样本进行测试,并将其用于评估概念证明(see video)。我现在正在寻找扩展的单笔触字体(包括汉字)以进一步评估。一个不太简单的解决方案可能是找到一种方法来创建跟随填充的笔触,然后使用简单的2D几何来评估首先要对哪个笔触进行动画处理(例如,中文规则在笔划顺序上非常清晰)。

Link to Playground on Github

  • 要使用XPCShowView函数,请执行以下操作:打开“文件导航器”和"file"
    实用程序检查器
  • 单击“操场”文件并在FUI中(选择
    在模拟器中运行)
  • 要访问助手编辑器:转到菜单 View >助手编辑器
  • 要查看资源/源,请在Finder中右键单击Playground文件并显示包内容
  • 如果Playground在打开时为空白,请将文件复制到桌面并重新打开(bug ??)

  • 游乐场代码
    import CoreText
    import Foundation
    import UIKit
    import QuartzCore
    import XCPlayground

    //research layers
    //var l:CALayer? = nil
    //var txt:CATextLayer? = nil
    //var r:CAReplicatorLayer? = nil
    //var tile:CATiledLayer? = nil
    //var trans:CATransformLayer? = nil
    //var b:CAAnimation?=nil

    // Setup playground to run in full simulator (⌘-0:Select Playground File; ⌘-alt-0:Choose option Run in Full Simulator)

    //approach 2 using a custom stroke font requires special font without an outline whose path is the actual fill
    var customFontPath = NSBundle.mainBundle().pathForResource("cwTeXFangSong-zhonly", ofType: "ttf")

    // Within the playground folder create Resources folder to hold fonts. NB - Sources folder can also be created to hold additional Swift files
    //ORTE1LOT.otf
    //NISC18030.ttf
    //cwTeXFangSong-zhonly
    //cwTeXHei-zhonly
    //cwTeXKai-zhonly
    //cwTeXMing-zhonly
    //cwTeXYen-zhonly

    var customFontData = NSData(contentsOfFile: customFontPath!) as! CFDataRef
    var error:UnsafeMutablePointer<Unmanaged<CFError>?> = nil
    var provider:CGDataProviderRef = CGDataProviderCreateWithCFData ( customFontData )
    var customFont = CGFontCreateWithDataProvider(provider) as CGFont!

    let registered = CTFontManagerRegisterGraphicsFont(customFont, error)

    if !registered {
    println("Failed to load custom font: ")

    }

    let string:NSString = "五"
    //"ABCDEFGHIJKLMNOPQRSTUVWXYZ一二三四五六七八九十什我是美国人"

    //use the Postscript name of the font
    let font = CTFontCreateWithName("cwTeXFangSong", 72, nil)
    //HiraMinProN-W6
    //WeibeiTC-Bold
    //OrachTechDemo1Lotf
    //XinGothic-Pleco-W4
    //GB18030 Bitmap

    var count = string.length

    //must initialize with buffer to enable assignment within CTFontGetGlyphsForCharacters
    var glyphs = Array<CGGlyph>(count: string.length, repeatedValue: 0)
    var chars = [UniChar]()

    for index in 0..<string.length {

    chars.append(string.characterAtIndex(index))

    }

    //println ("\(chars)") //ok

    //println(font)
    //println(chars)
    //println(chars.count)
    //println(glyphs.count)

    let gotGlyphs = CTFontGetGlyphsForCharacters(font, &chars, &glyphs, chars.count)

    //println(glyphs)
    //println(glyphs.count)

    if gotGlyphs {

    // loop and pass paths to animation function
    let cgpath = CTFontCreatePathForGlyph(font, glyphs[0], nil)

    //how to break the path apart?
    let path = UIBezierPath(CGPath: cgpath)
    //path.hashValue
    //println(path)

    // all shapes are closed paths
    // how to distinguish overlapping shapes, confluence points connected by line segments?
    // compare curve angles to identify stroke type
    // for curves that intersect find confluence points and create separate line segments by adding the linesegmens between the gap areas of the intersection

    /* analysis of movepoint

    This method implicitly ends the current subpath (if any) and
    sets the current point to the value in the point parameter.
    When ending the previous subpath, this method does not actually
    close the subpath. Therefore, the first and last points of the
    previous subpath are not connected to each other.

    For many path operations, you must call this method before
    issuing any commands that cause a line or curve segment to be
    drawn.
    */


    //CGPathApplierFunction should allow one to add behavior to each glyph obtained from a string (Swift version??)

    // func processPathElement(info:Void, element: CGPathElement?) {
    // var pointsForPathElement=[UnsafeMutablePointer<CGPoint>]()
    // if let e = element?.points{
    // pointsForPathElement.append(e)
    //
    // }
    // }
    //
    // var pathArray = [CGPathElement]() as! CFMutableArrayRef

    //var pathArray = Array<CGPathElement>(count: 4, repeatedValue: 0)

    //CGPathApply(<#path: CGPath!#>, <#info: UnsafeMutablePointer<Void>#>, function: CGPathApplierFunction)


    // CGPathApply(path.CGPath, info: &pathArray, function:processPathElement)

    /*
    NSMutableArray *pathElements = [NSMutableArray arrayWithCapacity:1];
    // This contains an array of paths, drawn to this current view
    CFMutableArrayRef existingPaths = displayingView.pathArray;
    CFIndex pathCount = CFArrayGetCount(existingPaths);
    for( int i=0; i < pathCount; i++ ) {
    CGMutablePathRef pRef = (CGMutablePathRef) CFArrayGetValueAtIndex(existingPaths, i);
    CGPathApply(pRef, pathElements, processPathElement);
    }
    */

    //given the structure
    let pathString = path.description
    // println(pathString)
    //regex patthern matcher to produce subpaths?
    //...
    //must be simpler method
    //...

    /*
    NOTES:
    Use assistant editor to view
    UIBezierPath String

    http://www.google.com/fonts/earlyaccess
    Stroke-based fonts
    Donald Knuth

    */
    // var redColor = UIColor.redColor()
    // redColor.setStroke()


    var pathLayer = CAShapeLayer()
    pathLayer.frame = CGRect(origin: CGPointZero, size: CGSizeMake(300.0,300.0))
    pathLayer.lineJoin = kCALineJoinRound
    pathLayer.lineCap = kCALineCapRound
    //pathLayer.backgroundColor = UIColor.whiteColor().CGColor
    pathLayer.strokeColor = UIColor.redColor().CGColor
    pathLayer.path = path.CGPath


    // pathLayer.backgroundColor = UIColor.redColor().CGColor

    // regarding strokeStart, strokeEnd
    /* These values define the subregion of the path used to draw the
    * stroked outline. The values must be in the range [0,1] with zero
    * representing the start of the path and one the end. Values in
    * between zero and one are interpolated linearly along the path
    * length. strokeStart defaults to zero and strokeEnd to one. Both are
    * animatable. */
    var pathAnimation = CABasicAnimation(keyPath: "strokeEnd")
    pathAnimation.duration = 10.0
    pathAnimation.fromValue = NSNumber(float: 0.0)
    pathAnimation.toValue = NSNumber(float: 1.0)

    /*
    var fillAnimation = CABasicAnimation (keyPath: "fill")
    fillAnimation.fromValue = UIColor.blackColor().CGColor
    fillAnimation.toValue = UIColor.blueColor().CGColor
    fillAnimation.duration = 10.0
    pathLayer.addAnimation(fillAnimation, forKey: "fillAnimation") */

    //given actual behavior of boundary animation, it is more likely that some other animation will better simulate a written stroke

    var someView = UIView(frame: CGRect(origin: CGPointZero, size: CGSizeMake(300.0, 300.0)))
    someView.layer.addSublayer(pathLayer)


    //SHOW VIEW IN CONSOLE (ASSISTANT EDITOR)
    XCPShowView("b4Animation", someView)

    pathLayer.addAnimation(pathAnimation, forKey: "strokeEndAnimation")

    someView.layer.addSublayer(pathLayer)

    XCPShowView("Animation", someView)




    }

    最佳答案

    您想看一下CGPathApply(这是对您更精确的问题的简短回答)。您为它提供一个函数,它将为路径的每个元素(这些元素为直线,圆弧和闭合线)调用该函数。您可以使用它来重构每个已关闭的项目,并将它们存储到列表中。然后,您可以找出每个项目的绘制方向(我认为这实际上可能是最难的部分),而不是使用strokeStart/strokeEnd一个子路径,每个子路径将其绘制为带有蒙版的图层并将蒙版移动到整个图层上。

    关于ios - 如何使用Swift/iOS为人类笔画制作动画?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29365732/

    24 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com