PDFクラウドアノテーションの背後にあるアルゴリズムは何ですか?

レイス

いくつかのPDF注釈アプリケーション(Adobe Acrobat、Bluebeamなど)には、ポリゴンの周りに雲のパターンを作成するためのアルゴリズムがあることに気づきました。

PDFでのクラウド注釈

このポリゴンの頂点をドラッグすると、雲のパターンが再計算されます。

PDFで変更されたクラウド注釈

円弧がポリゴンをラップするように再計算される方法に注目してください。それらは引き伸ばされたり歪んだりしていません。これを定義するために使用されるアルゴリズムは、業界標準のようです。いくつかのPDFエディターを使用すると、これを作成できます。それぞれのエディターで、頂点をドラッグしたときに雲の弧が同じように見えます。

これを複製するWPFサンプルアプリケーションを作成しようとしていますが、クラウドパターンを生成するためのドキュメントがどこにも見つからないようです。

I'm quite fluent with graphic design and 2D programming, and I'm capable of creating the tool to drag the vertices around, but I need help with figuring out how to draw these arcs. It looks like a series of ArcSegments in a PathGeometry.

So my question would be, what's the algorithm to create these arcs around a polygon?

or

Where can I find the documentation for these industry-standard PDF patterns, drawings, and/or annotations? (Cloud, arrows, borders, etc)

M Oehm

The clouds in your sketches are just a series of circles drawn along each polygon edge with a certain overlap.

An easy way to draw the filled basic cloud shape would be to first fill the polygon and then draw the circles on top of the filled polygon.

That approach falls flat when you want to fill the cloud with a partially transparent colour, because the overlap of the circles with each other and with the base polygon will be painted twice. It will also miss the small cartoon-style overshoots on the cloud curves.

A better way to draw the cloud is to create all circles first and then determine the intersecting angles of each circle with its next neighbour. You can then create a path with circle segments, which you can fill. The outline consists of independent arcs with a small offset for the end angle.

In your example, the distance between the cloud arcs is static. It is easy to make the arcs at polygon vertices coincide by making that distance variable and by enforcing that the polygon edge is evenly divisible by that distance.

An example implementation in JavaScript (without the polygon dragging) is below. I'm not familiar with C#, but I think the basic algorithm is clear. The code is a complete web page, that you can save and display in browser that supports the canvas; I've tested it in Firefox.

The function to draw the cloud takes an object of options such as the radius, the arc distance and the overshoot in degrees. I haven't tested degenerate cases like small polygons, but in the extreme case the algorithm should just draw a single arc for each polygon vertex.

The polygon must be defined clockwise. Otherwise, the cloud will be more like a hole in cloud cover. That would be a nice feature, if there weren't any artefacts around the corner arcs.

編集以下にクラウドアルゴリズムの簡単なオンラインテストページ提供しましたこのページでは、さまざまなパラメーターを試すことができます。また、アルゴリズムの欠点もうまく示しています。(FFとChromeでテスト済み。)

アーティファクトは、開始角度と終了角度が適切に決定されていない場合に発生します。非常に鈍角の場合、コーナーの隣の円弧の間に交差がある場合もあります。私はそれを修正していませんが、私もそれほど多くのことを考えていません。)

<!DOCTYPE html>

<html>
<head>
<meta charset="utf-8" />
<title>Cumulunimbus</title>
<script type="text/javascript">

    function Point(x, y) {
        this.x = x;
        this.y = y;
    }

    function get(obj, prop, fallback) {
        if (obj.hasOwnProperty(prop)) return obj[prop];
        return fallback;
    }

    /*
     *      Global intersection angles of two circles of the same radius
     */
    function intersect(p, q, r) {
        var dx = q.x - p.x;
        var dy = q.y - p.y;

        var len = Math.sqrt(dx*dx + dy*dy);
        var a = 0.5 * len / r;

        if (a < -1) a = -1;
        if (a > 1) a = 1;

        var phi = Math.atan2(dy, dx);
        var gamma = Math.acos(a);

        return [phi - gamma, Math.PI + phi + gamma];
    }

    /*
     *      Draw a cloud with the given options to the given context
     */
    function cloud(cx, poly, opt) {        
        var radius = get(opt, "radius", 20);
        var overlap = get(opt, "overlap", 5/6);
        var stretch = get(opt, "stretch", true);



        // Create a list of circles

        var circle = [];        
        var delta = 2 * radius * overlap;

        var prev = poly[poly.length - 1];
        for (var i = 0; i < poly.length; i++) {
            var curr = poly[i];

            var dx = curr.x - prev.x;
            var dy = curr.y - prev.y;

            var len = Math.sqrt(dx*dx + dy*dy);

            dx = dx / len;
            dy = dy / len;

            var d = delta;

            if (stretch) {
                var n = (len / delta + 0.5) | 0;

                if (n < 1) n = 1;
                d = len / n;
            }

            for (var a = 0; a + 0.1 * d < len; a += d) {
                circle.push({
                    x: prev.x + a * dx,
                    y: prev.y + a * dy,
                });
            }

            prev = curr;
        }



        // Determine intersection angles of circles

        var prev = circle[circle.length - 1];
        for (var i = 0; i < circle.length; i++) {
            var curr = circle[i];
            var angle = intersect(prev, curr, radius);

            prev.end = angle[0];
            curr.begin = angle[1];

            prev = curr;
        }



        // Draw the cloud

        cx.save();

        if (get(opt, "fill", false)) {
            cx.fillStyle = opt.fill;

            cx.beginPath();
            for (var i = 0; i < circle.length; i++) {
                var curr = circle[i];

                cx.arc(curr.x, curr.y, radius, curr.begin, curr.end);
            }
            cx.fill();
        }

        if (get(opt, "outline", false)) {
            cx.strokeStyle = opt.outline;
            cx.lineWidth = get(opt, "width", 1.0);

            var incise = Math.PI * get(opt, "incise", 15) / 180;

            for (var i = 0; i < circle.length; i++) {
                var curr = circle[i];

                cx.beginPath();
                cx.arc(curr.x, curr.y, radius,
                    curr.begin, curr.end + incise);
                cx.stroke();
            }
        }

        cx.restore();
    }

    var poly = [
        new Point(250, 50),
        new Point(450, 150),
        new Point(350, 450),
        new Point(50, 300),
    ];

    window.onload = function() {
        cv = document.getElementById("cv");
        cx = cv.getContext("2d");

        cloud(cx, poly, {
            fill: "lightblue",        // fill colour
            outline: "black",         // outline colour
            incise: 15,               // overshoot in degrees
            radius: 20,               // arc radius
            overlap: 0.8333,          // arc distance relative to radius
            stretch: false,           // should corner arcs coincide?
        });
    }

</script>
</head>

<body>
<canvas width="500" height="500" id="cv"></canvas>
</body>

</html>

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

分類Dev

Cassandraのトークン関数の背後にあるアルゴリズムは何ですか?

分類Dev

Linuxのfactorコマンドの背後にあるアルゴリズムは何ですか?

分類Dev

ホワイトバランスアルゴリズムの背後にある数学は何ですか?

分類Dev

Rasa NLUの背後にあるアルゴリズムは何ですか?

分類Dev

Random.next()の背後にあるアルゴリズムは何ですか?

分類Dev

Random.next()の背後にあるアルゴリズムは何ですか?

分類Dev

Reactの「diffing」ヒューリスティックアルゴリズムの背後にある動機は何ですか?

分類Dev

Photoshopの「白黒」調整レイヤーの背後にあるアルゴリズムは何ですか?

分類Dev

Rコアの `split`関数の背後にあるアルゴリズムは何ですか?

分類Dev

フォトショップパレットナイフ効果の背後にあるアルゴリズムは何ですか?

分類Dev

Adobe Lightroomでカラーノイズリダクションに使用されているアルゴリズムは何ですか?

分類Dev

JavaのMath.pow()の背後にあるアルゴリズムは何ですか

分類Dev

Javaガベージコレクションの背後にある理論とアルゴリズム

分類Dev

GROUP USING'collected 'および' merge 'の背後にあるアルゴリズムは何ですか

分類Dev

選択範囲の gimp フェザー エッジの背後にあるアルゴリズムは何ですか?

分類Dev

Java:アプリケーションを介してクライアントをロードバランサーの背後にある同じセッション/ノードにリダイレクトできますか?

分類Dev

関数ツリーにノードを挿入するアルゴリズムの欠陥は何ですか?

分類Dev

再帰的アルゴリズムをカバーするチェッカーボードの背後にある直感は何ですか?また、そのようなアルゴリズムの定式化をどのように上手く行うことができますか?

分類Dev

厳密なエイリアシングルールの背後にある理論的根拠は何ですか?

分類Dev

GolangのGoルーチンの背後にあるアーキテクチャは何ですか?

分類Dev

デフォルトでインストールされたアプリケーションの背後にある根拠は何ですか?

分類Dev

Intelのリアルセンス深度センサーの背後にあるテクノロジーはどれですか?

分類Dev

eコマースレコメンデーションシステムのknnアルゴリズムに最適なkは何ですか

分類Dev

Amazon GPUインスタンスの背後にあるハードウェアは何ですか?

分類Dev

クラスター化されたノードの無制限のブランチを作成するためのアルゴリズムはありますか?

分類Dev

リアルタイム機能のWebアプリケーションで使用するフレームワーク/テクノロジーは何ですか?

分類Dev

std :: seed_seqの背後にあるアルゴリズムは定義されていますか?

分類Dev

Golangの「すべてのゴルーチンが眠っている-デッドロック!」エラーのアルゴリズムは何ですか?

分類Dev

アルゴリズムの背後にある数学の説明

Related 関連記事

  1. 1

    Cassandraのトークン関数の背後にあるアルゴリズムは何ですか?

  2. 2

    Linuxのfactorコマンドの背後にあるアルゴリズムは何ですか?

  3. 3

    ホワイトバランスアルゴリズムの背後にある数学は何ですか?

  4. 4

    Rasa NLUの背後にあるアルゴリズムは何ですか?

  5. 5

    Random.next()の背後にあるアルゴリズムは何ですか?

  6. 6

    Random.next()の背後にあるアルゴリズムは何ですか?

  7. 7

    Reactの「diffing」ヒューリスティックアルゴリズムの背後にある動機は何ですか?

  8. 8

    Photoshopの「白黒」調整レイヤーの背後にあるアルゴリズムは何ですか?

  9. 9

    Rコアの `split`関数の背後にあるアルゴリズムは何ですか?

  10. 10

    フォトショップパレットナイフ効果の背後にあるアルゴリズムは何ですか?

  11. 11

    Adobe Lightroomでカラーノイズリダクションに使用されているアルゴリズムは何ですか?

  12. 12

    JavaのMath.pow()の背後にあるアルゴリズムは何ですか

  13. 13

    Javaガベージコレクションの背後にある理論とアルゴリズム

  14. 14

    GROUP USING'collected 'および' merge 'の背後にあるアルゴリズムは何ですか

  15. 15

    選択範囲の gimp フェザー エッジの背後にあるアルゴリズムは何ですか?

  16. 16

    Java:アプリケーションを介してクライアントをロードバランサーの背後にある同じセッション/ノードにリダイレクトできますか?

  17. 17

    関数ツリーにノードを挿入するアルゴリズムの欠陥は何ですか?

  18. 18

    再帰的アルゴリズムをカバーするチェッカーボードの背後にある直感は何ですか?また、そのようなアルゴリズムの定式化をどのように上手く行うことができますか?

  19. 19

    厳密なエイリアシングルールの背後にある理論的根拠は何ですか?

  20. 20

    GolangのGoルーチンの背後にあるアーキテクチャは何ですか?

  21. 21

    デフォルトでインストールされたアプリケーションの背後にある根拠は何ですか?

  22. 22

    Intelのリアルセンス深度センサーの背後にあるテクノロジーはどれですか?

  23. 23

    eコマースレコメンデーションシステムのknnアルゴリズムに最適なkは何ですか

  24. 24

    Amazon GPUインスタンスの背後にあるハードウェアは何ですか?

  25. 25

    クラスター化されたノードの無制限のブランチを作成するためのアルゴリズムはありますか?

  26. 26

    リアルタイム機能のWebアプリケーションで使用するフレームワーク/テクノロジーは何ですか?

  27. 27

    std :: seed_seqの背後にあるアルゴリズムは定義されていますか?

  28. 28

    Golangの「すべてのゴルーチンが眠っている-デッドロック!」エラーのアルゴリズムは何ですか?

  29. 29

    アルゴリズムの背後にある数学の説明

ホットタグ

アーカイブ