Illustratorでオブジェクトの面積が全体を占める割合を求めるスクリプトを作成&シェア(V2)

Close Up Photography of Brown and White Kitten

先日はIllustratorで選択されたオブジェクトが全体の面積を占める割を求めるスクリプトの出来上がるまでの取り組みを記録した。

それを2点改善したのでその取組をここに記す。

修正1:曲線面積の新しい求め方

まず先日のスクリプトでは、幅ありの線の面積を求める機能を設けていたが、「線の長さ*幅」という単純な数式のため、曲線の面積を正確に求められない。線の長さも求めにくいし、線の両側の面積が異なっているからだ。

曲線は面積を求めにくい

スクリプトの改修も依頼してみたが、返ってくるプログラムを見てこれは道のり遠いと勘づいたので、別の方法を模索することにした。

結論を言うと、Illustratorの「パスのアウトライン」機能を使うと、線を簡単に図形に変えることができることを発見した。図形に変更しておけば、どんな複雑な形も先日のスクリプトの面積を求める機能で面積を取得できるので、線の面積を計算し取得する部分は不要になる。

ちょっと見づらいが、上の画像では、左が線の状態、右がパスのアウトライン後の図形の状態だ。ピンクの丸でカラー設定のところを囲んで強調しているので、Illustratorがわかる方ならわかるはずだ。ちょっと荒くなっているようだが、面積を計算する分には違いがない。

修正2:複数オブジェクト選択機能追加

もう1つの改善点は、1つしかオブジェクトが選択できない仕様だったのを、複数のオブジェクトを選択した場合に、その面積を合算する仕様に直してもらったことだ。これはforループが追加されているだけだから、特筆することはない。

ということで、先日のスクリプトから線の面積を計算する機能を削除し、複数オブジェクト選択の機能を追加したコードは次のとおりだ。コメントアウトの部分が変更のある箇所だ。

JavaScript
function calculatePathArea(pathItem) {
    var area = Math.abs(pathItem.area); // パスアイテムの面積を取得。塗り部分のみ、ストロークは対象外
    
    // パスが閉じていない場合は線の面積を追加
    // if (!pathItem.closed) {
    //     var length = pathItem.length;
    //     var strokeWidth = pathItem.strokeWidth;
    //     var strokeArea = length * strokeWidth;
    //     area = strokeArea;
    // }
    
    //alert ('area: ' + area);

    return area;
}

function calculateCompoundPathArea(compoundPath) {
    var totalArea = 0;

    for (var i = 0; i < compoundPath.pathItems.length; i++) {
        totalArea += calculatePathArea(compoundPath.pathItems[i]);
    }

    alert ('totalArea: ' + totalArea);

    return totalArea;
}

// function calculateOverlapArea(pathItems) {
//     // 全てのパスが同じ点で交差し、同じ線幅を持つと仮定
//     var strokeWidth = pathItems[0].strokeWidth;
//     var overlapArea = strokeWidth * strokeWidth;

//     return overlapArea;
// }

function calculateSelectedShapeAreaRatio() {
    if (app.documents.length === 0) {
        alert("ドキュメントが開いていません!");
        return;
    }

    var doc = app.activeDocument;
    var selection = doc.selection;

    if (selection.length === 0) {
        alert("形状を選択してください。");
        return;
    }

    // 変更箇所: 合計面積を計算するための変数を初期化
    var totalSelectedArea = 0;

    // 変更箇所: 選択されたオブジェクトをループして面積を計算
    for (var i = 0; i < selection.length; i++) {
        var selectedShape = selection[i];

        // 選択されたオブジェクトが有効なパスアイテムまたはコンパウンドパスアイテムか確認
        var selectedArea;
        if (selectedShape.typename === "CompoundPathItem") {
            selectedArea = calculateCompoundPathArea(selectedShape);
        } else if (selectedShape.typename === "PathItem") {
            selectedArea = calculatePathArea(selectedShape);
        } else {
            alert("選択されたオブジェクトは有効なパスアイテムまたはコンパウンドパスアイテムではありません。");
            return;
        }

        // 変更箇所: 各選択オブジェクトの面積を合計
        totalSelectedArea += selectedArea;
    }

    // 選択されたオブジェクトが交差するパスを持つコンパウンドパスアイテムの場合、交差面積を減算
    // if (selectedShape.typename === "CompoundPathItem" || selectedShape.typename === "PathItem") {
    //     var pathItems = (selectedShape.typename === "CompoundPathItem") ? selectedShape.pathItems : [selectedShape];
    //     var overlapArea = calculateOverlapArea(pathItems);
    //     selectedArea -= overlapArea;
    // }

    // アートボードの面積を計算
    var artboard = doc.artboards[doc.artboards.getActiveArtboardIndex()];
    var artboardRect = artboard.artboardRect;
    var artboardWidth = artboardRect[2] - artboardRect[0];
    var artboardHeight = artboardRect[1] - artboardRect[3];
    var artboardArea = artboardWidth * artboardHeight;

    if (isNaN(artboardArea) || isNaN(totalSelectedArea)) {
        alert("面積の計算に失敗しました。有効なオブジェクトを確認してください。");
        return;
    }

    var ratio = (totalSelectedArea / artboardArea) * 100;

    alert("選択された形状の面積: " + totalSelectedArea.toFixed(4) + " px²\n" +
          "選択された形状はアートボード全体の " + ratio.toFixed(2) + "% を占めています。\n" +
          "アートボードの面積: " + artboardArea.toFixed(4) + " px²"); 
}

calculateSelectedShapeAreaRatio();

要らない機能のコメントアウト行を削除し、JSDoc説明を追加したVersion 2のコードをシェアする。

今回は以上だ。