Keynote書類の現在のスライド(ページ)上に存在する表オブジェクトの重なり合いを検出するAppleScriptです。
Cocoa Scripting Course #4のチェックを行なっていたら、表オブジェクトが重なり合っていたページがあってヘコみました(再チェック中です)。
これを自動でチェックするためのAppleScriptを書いてみました。とりあえず、現在表示しているスライド(ページ)を対象に。最終的には、開始と終了のスライドの番号を与えておくと、その間のスライドをすべてチェックできるとよいでしょう。
CocoaのNSRect同士であれば、重なり合いを検出できるので大変便利です。Keynote上の表オブジェクトから、位置情報と大きさの情報を取得すれば、簡単に目的のデータ(配列に入れたNSRect)を作れることでしょう。
ただし、NSIntersectionRectでNSRect同士の衝突検出を行えるとしても、1対1でしかチェックできないようなので、検出された表同士のすべての衝突チェック組み合わせを行うべく、順列組み合わせペア・パターンを計算する部品を急遽作って(以前作った、Permutation計算とは仕様が違うので)、2つずつ表(から作ったNSRect)を取り出して矩形座標の衝突判定を行なっています。
Keynoteの座標系は「左上」が原点座標で、Cocoaの座標系は左下のはずで….macOS 12で左上になったという話もありますが、実戦投入してみたら衝突が発生していないスライドでも衝突が検出されていたので、このあたり修正する必要があるかもしれません。
Keynoteのスライド上の表の配置状況をCocoaのNSRectで表現し、デバッグ用に画像で表示させてみました。重なりをシミュレーションするだけなら、とくに問題はなさそうです。
→ 原因がわかりました。表の座標とサイズから作ったNSRect同士を重なり合い計算するための、順列組み合わせパターン計算ルーチンで1×1とか2×2とかの「同じNSRect同士」の重なりを計算するようなパターンまで出力していたのが原因です。
つまり、現状では「複数の表オブジェクトが入っているスライド」を検出するだけの計算を行なってしまっているようです。
--> {{1, 1}, {1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 1}, {2, 2}, {2, 3}, {2, 4}, {2, 5}, {3, 1}, {3, 2}, {3, 3}, {3, 4}, {3, 5}, {4, 1}, {4, 2}, {4, 3}, {4, 4}, {4, 5}, {5, 1}, {5, 2}, {5, 3}, {5, 4}, {5, 5}}
と計算してしまうところを、
--> {{1, 2}, {1, 3}, {1, 4}, {1, 5}, {2, 1}, {2, 3}, {2, 4}, {2, 5}, {3, 1}, {3, 2}, {3, 4}, {3, 5}, {4, 1}, {4, 2}, {4, 3}, {4, 5}, {5, 1}, {5, 2}, {5, 3}, {5, 4}}
のように、同じアイテム同士の組み合わせになるパターンだけを除外してあげればよかったわけです。自分で資料を作ってみてわかりました。
あとは、3×5と5×3は計算としては同じ意味なので、こういう重複パターンを除去してあげる必要があるのですが…重なりの「個数」を数えるのであるのであればともかく、重なりを「検出」するだけなら重複除去まではする必要がないでしょう。
AppleScript名:現在のスライド上の表オブジェクトの重なり合い(2つ以上対応)を検出 v2.scptd |
— – Created by: Takaaki Naganoya – Created on: 2022/04/03 — – Copyright © 2022 Piyomaru Software, All Rights Reserved — use AppleScript version "2.4" — Yosemite (10.10) or later use framework "Foundation" use scripting additions tell application "Keynote" tell front document tell current slide set tList to every table if length of tList < 2 then return false –複数の「表」がなかったら衝突は発生していない –表の座標とサイズによりNSRectangleを作成する set bList to {} repeat with i in tList set j to contents of i tell j set {xPos, yPos} to position set aWidth to width set aHeight to height set aRect to makeRect(xPos, yPos, aWidth, aHeight) of me end tell set the end of bList to aRect end repeat –作成したNSRectangleの順列組み合わせペア・パターンを作成して、NSRectangle同士の衝突判定を順次行う set aLen to length of bList set permuList to retPairPermutations(aLen) of me set corruptList to {} repeat with i in permuList copy i to {i1, i2} set rectRes to detectRectanglesCollision(item i1 of bList, item i2 of bList) of me if rectRes = true then return true –表同士の衝突が発生している end repeat return false –表同士の衝突は発生していない end tell end tell end tell on makeRect(xPos, yPos, aWidth, aHeight) return current application’s NSMakeRect(xPos, yPos, aWidth, aHeight) end makeRect –NSRect同士の衝突判定 on detectRectanglesCollision(aRect, bRect) set a1Res to (current application’s NSIntersectionRect(aRect, bRect)) as {record, list} set tmpClass to class of a1Res if tmpClass = record then –macOS 10.10, 10.11, 10.12 return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}}) else if tmpClass = list then –macOS 10.13 or later return not (a1Res = {{0.0, 0.0}, {0.0, 0.0}}) end if end detectRectanglesCollision –1から任意の数までのアイテムで、2個ずつの組み合わせのすべての順列組み合わせパターンを計算して返す on retPairPermutations(aMax) set aList to {} repeat with x from 1 to aMax repeat with xx from 1 to aMax set tmpItem to {x, xx} if tmpItem is not in aList then set the end of aList to tmpItem end if end repeat end repeat return aList end retPairPermutations |