2016-05-01 17 views
3

パスのSVG記述を変換する必要があります。何かのように:そのパスに沿って下落するだろうすべてのピクセルのリストにPythonでSVGパスをピクセル座標(単なるラスターではない)に補間する方法

M400 597 C235 599 478 607 85 554 C310 675 2 494 399 718 C124 547 569 828 68 400 C-108 317 304 703 96 218 L47 215 L400 290 C602 -146 465 467 550 99 L548 35 L706 400 L580 686 C546 614 591 672 529 629 L400 597 Z

(キャンバスと仮定すると、モニタのサイズであるあなたが見ることができるように、パスは私が量で作業する必要があります。落書き、非常に複雑である。理想的には、私はすなわち、そのようなパスを生成し、ピクセルごとの記述に全体の事を変換したい。

p= [(403, 808), (403, 807), (403, 805), (403, 802), (403, 801), (403, 800), (403, 799), 
(403, 797), (403, 794), (403, 792), (402, 789), (401, 787), (400, 785), (399, 784), 
(399, 783), (398, 782)] # ... it'd be much longer, but you get the idea 

また、私が持つコンテンツとしてだろう任意カーブとラインの構成要素を持つパスを生成する手段(SVGは単に私はこれまでこれを達成しました)。コンテキストはちょっと変わったものです。それは認知心理学の実験のためのものです。特定の規則に従って生成されたパスを横断するドットを徐々にアニメートする必要がある場合は、のパスをピクセルデータとしてエクスポートします。

アニメーションを行うには、パスに沿った各x、y位置でドットを再描画するだけです。したがって、そのリストは必要ありません。

私の数学のスキルはあまり良くありません - CSではなく、デザインからコードを書くようになりました。パスはかなり複雑になります。これらのポイントを数学だけで計算することは...おそらく私を超えてはいないでしょう私が目指しているよりも要求が厳しい。

ライブラリ、トリック、戦略 - すべて歓迎&が高く評価されました。

+0

この種の歪みを必要とせずに、通常のSVGでパスに沿ってドットを移動することができます。カスタムストロークダッシュ配列を使用して、オフセットをアニメートすることで、これを行うことができます。あなたのドットに適した文字を見つけることができれば、textPathを使ってもできます。 –

+0

私はあなたに従っていますが、私はまた、データファイルの実際のピクセル位置が必要です。これは、プロジェクトの科学的ニーズの制約です。しかし、私は実際には、これについての2つの同様の質問を使用してこれを分解した可能性があると思っています。 – Jonline

答えて

0

回答はほとんどdifferent postで、unutbu(2番目の回答)です。

これは私の上記の問題を解決するためのいくつかの追加機能を備えた彼の基本的な機能の私の修正です。私は線分のための同様の関数を書く必要がありますが、それは明らかにはるかに簡単であり、それらの間に上記のように私の目標を達成するために曲線と線分の任意の組み合わせを組み合わせることができるでしょう。

def pascal_row(n): 
    # This is over my designer's brain, but unutbu says: 
    # "This returns the nth row of Pascal's Triangle" 
    result = [1] 
    x, numerator = 1, n 
    for denominator in range(1, n//2+1): 
     # print(numerator,denominator,x) 
     x *= numerator 
     x /= denominator 
     result.append(x) 
     numerator -= 1 
    if n&1 == 0: 
     # n is even 
     result.extend(reversed(result[:-1])) 
    else: 
     result.extend(reversed(result)) 
    return result 


def bezier_interpolation(origin, destination, control_o, control_d=None): 
     points = [origin, control_o, control_d, destination] if control_d else [origin, control_o, destination] 
     n = len(points) 
     combinations = pascal_row(n - 1) 

     def bezier(transitions): 
      # I don't really understand any of this math, but it works! 
      result = [] 
      for t in transitions: 
       t_powers = (t ** i for i in range(n)) 
       u_powers = reversed([(1 - t) ** i for i in range(n)]) 
       coefficients = [c * a * b for c, a, b in zip(combinations, t_powers, u_powers)] 
       result.append(
        list(sum([coef * p for coef, p in zip(coefficients, ps)]) for ps in zip(*points))) 
      return result 


     def line_segments(points, size): 
      # it's more convenient for my purposes to have the pairs of x,y 
      # coordinates that eventually become the very small line segments 
      # that constitute my "curves 
      for i in range(0, len(points), size): 
       yield points[i:i + size] 


     # unutbu's function creates waaay more points than needed, and 
     # these extend well through the "destination" point I want to end at, so, 
     # I keep inspecting the line segments until one of them passes through 
     # my intended stop point (ie. "destination") and then manually stop 
     # collecting, returning the subset I want; probably not efficient, 
     # but it works 
     break_next = False 
     segments = [] 
     for pos in line_segments(bezier([0.01 * t for t in range(101)]), 2): 
      if break_next: 
       segments.append([break_next, destination]) 
       break 
      try: 
       if [int(i) for i in pos[0]] == destination: 
        break_next = pos[0] 
        continue 
       segments.append(pos) 
      except IndexError: 
       # not guaranteed to get an even number of points from bezier() 
       break 
      return segments 
0

奇妙な目的のために、SVGパスを離散ポイントに変換する必要がありました。どうやらそれを行うライトライブラリはありません。私は自分のパーサを作成してしまった。

ほとんどの場合、入力ファイルはベジェ曲線で構成されています。

def cubic_bezier_sample(start, control1, control2, end): 
    inputs = np.array([start, control1, control2, end]) 
    cubic_bezier_matrix = np.array([ 
     [-1, 3, -3, 1], 
     [ 3, -6, 3, 0], 
     [-3, 3, 0, 0], 
     [ 1, 0, 0, 0] 
    ]) 
    partial = cubic_bezier_matrix.dot(inputs) 

    return (lambda t: np.array([t**3, t**2, t, 1]).dot(partial)) 

def quadratic_sample(start, control, end): 
    # Quadratic bezier curve is just cubic bezier curve 
    # with the same control points. 
    return cubic_bezier_sample(start, control, control, end) 

10個のサンプルを生成するために次のように使用することができます:

n = 10 
curve = cubic_bezier_sample((50,0), (50,100), (100,100), (50,0)) 
points = [curve(float(t)/n) for t in xrange(0, n + 1)] 

コードがnumpyのを必要と私はそのための迅速な機能を書きました。また、必要ならばnumpyなしでドットプロダクトを実行することもできます。 svg.pathでパラメータを取得できました。

0

svg path interpolator JavaScriptライブラリは、svgパスをポリゴンポイントデータに変換し、サンプルサイズと忠実度のオプションを備えています。このライブラリは完全なSVG仕様をサポートしており、パス上のトランスフォームを考慮します。これはsvg入力を受け取り、補間された点を表すJSONを生成します。

関連する問題