Archive for the 'NSRect' Category

2017/07/07 Keynoteの現ページと次ページで場所が被っていても始点座標が異なるオブジェクトの始点座標をそろえる

編集中のKeynote書類で現在のスライドと次のスライド上の指定した種類のオブジェクトの座標情報をスキャンして、「重なっているが原点座標が異なる」ものを検出して原点座標を同じにそろえるAppleScriptです。

2017-07-07-13_06_20.gif

Keynoteで資料を使っていて、(複数ページ間で同じ場所に存在すべき)オブジェクトの位置が微妙にズレていることが気になることがあります。

ただ、いちいち座標情報をひろって手で修正するのは面倒なので、AppleScriptで自動修正させてみました。

重なっているオブジェクト同士であっても、始点座標が同じものは無視します(修正する必要はないので)。

Script実行時にチェック対象の2ページのうち、最初のページを表示していることを想定しています。

オブジェクトの領域の重なり判定は2つだけを想定しています。それ以上の個数のオブジェクトの重なりは無視しています。

KeynoteのAppleScript用語辞書がselection(選択中のオブジェクト)を取得できないという「残念な点」があるので、そこが重ね重ねも残念です。

AppleScript名:Keynoteの現ページと次ページで場所が被っていても始点座標が異なるオブジェクトの始点座標をそろえる
– Created 2017-07-07 by Takaaki Naganoya
– 2017 Piyomaru Software
– v1:オーバーラップしているオブジェクトの個数が2個のみの状況を想定
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4718

tell application “Keynote”
  tell front document
    set sNum to slide number of (current slide)
  end tell
end tell

–表示中のページ(slide)と、その次のページ(slide)で、
–指定オブジェクト(shape)の座標情報をリストアップ
set {rect1, obj1} to getObjInfoList(sNum, “shape”) of me –現在のページ(slide)
set {rect2, obj2} to getObjInfoList(sNum + 1, “shape”) of me –現在+1ページ

set hitRect to {} –衝突していつつもイコールではないオブジェクトの座標情報を入れる
set hitObj to {} –衝突しているオブジェクト(最初のページ、次のページ)をペアで入れる

set p1Count to 1

–表示中のページ(slide)と、その次のページ(slide)で、
–重なっていつつも始点座標が異なるオブジェクト(shape)を総当たりでリストアップ
tell application “Keynote”
  tell front document
    repeat with i in rect1
      set j to contents of i
      
      
set p2Count to 1
      
      
repeat with ii in rect2
        set jj to contents of ii
        
        
–指定オブジェクト同士の領域が重なっているかどうかチェック
        
set aRes to detectRectanglesCollision(j, jj) of me
        
–始点座標がイコールかどうかチェック(イコールのものは修正不要)
        
set origRes to (origin of j) = (origin of jj)
        
        
if (aRes = true) and (origRes = false) then
          set the end of hitRect to j
          
set the end of hitObj to {contents of item p1Count of obj1, contents of item p2Count of obj2}
        end if
        
        
set p2Count to p2Count + 1
        
      end repeat
      
      
set p1Count to p1Count + 1
    end repeat
  end tell
end tell

–current slideを2ページ目に変更
set cRes to changeCurrentSlide(sNum + 1) of me

–オーバーラップしていつつも始点座標が異なるアイテムの個数を数える
set tCount to count every item of hitRect

tell application “Keynote”
  tell front document
    tell current slide
      repeat with i from 1 to tCount
        set curPos to contents of item i of hitRect
        
set curOrig to origin of curPos
        
set curOrigX to x of curOrig
        
set curOrigY to y of curOrig
        
        
set curObj to contents of second item of item i of hitObj
        
set position of curObj to {curOrigX, curOrigY}
      end repeat
    end tell
  end tell
end tell

–最前面のKeynote書類の指定スライド(page)上の指定オブジェクトの情報(座標情報、オブジェクト情報)を返す
on getObjInfoList(aPage, objClassStr as string)
  set rectList to {}
  
set objList to {}
  
  
set cRes to changeCurrentSlide(aPage) of me
  
if cRes = false then error “Slide Range Error”
  
  
tell application “Keynote”
    tell front document
      tell current slide
        set aList to every iWork item
        
        
repeat with i in aList
          set aClass to (class of i) as string
          
          
if aClass = objClassStr then
            set aWidth to width of i
            
set aHeight to height of i
            
set {aPosX, aPosY} to position of i
            
set aRect to {origin:{x:aPosX, y:aPosY}, |size|:{|width|:aWidth, |height|:aHeight}}
            
            
set the end of rectList to aRect
            
set the end of objList to i
          end if
        end repeat
      end tell
    end tell
  end tell
  
  
return {rectList, objList}
end getObjInfoList

–NSRect同士の衝突判定
on detectRectanglesCollision(aRect, bRect)
  set a1Res to current application’s NSIntersectionRect(aRect, bRect)
  
return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}})
end detectRectanglesCollision

–表示中のスライド(ページ)を変更する
on changeCurrentSlide(targPageNum as integer)
  try
    tell application “Keynote”
      tell front document
        set sCount to count every slide
        
if targPageNum < 1 then return false –under check
        
if sCount < targPageNum then return false –over check
        
set current slide to slide targPageNum
        
return true
      end tell
    end tell
  on error
    return false
  end try
end changeCurrentSlide

★Click Here to Open This Script 

2017/06/22 指定矩形内に含まれるデータをリストで返す v3

指定矩形座標内に指定座標が含まれるかどうかを判定するAppleScriptです。

NSPointInRectを見つけて、NSRectの中にNSPointが含まれるかどうかチェックできることがわかりました(汗)

→ 矩形座標(NSRect)同士の衝突判定はこちら

AppleScript名:指定矩形内に含まれるデータをリストで返す v3
– Created 2017-06-22 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4702

set aList to {{507, 162}, {338, 166}, {389, 166}, {448, 166}, {286, 110}, {504, 109}, {558, 108}, {341, 113}, {394, 115}, {447, 112}, {234, 107}, {611, 110}, {286, 58}, {501, 63}, {556, 58}, {337, 59}, {391, 60}, {448, 63}, {611, 58}}

set rangeList to {{500, 100}, {550, 180}} –{{x1,y1}, {x2,y2}}
set resList to withinRange(rangeList, aList) of me
–>  {{507, 162}, {504, 109}}

on withinRange(rangeList as list, targetList as list)
  set aRect to makeNSRect(rangeList) of me
  
  
set includedList to {}
  
repeat with i in targetList
    copy i to {x, y}
    
set aPoint to current application’s NSMakePoint(x, y)
    
set aRes to (current application’s NSPointInRect(aPoint, aRect)) as boolean
    
    
if aRes = true then
      set the end of includedList to contents of i
    end if
  end repeat
  
  
return includedList
end withinRange

on makeNSRect(aList as list)
  try
    copy aList to {{x1, y1}, {x2, y2}}
    
set xWidth to (x2 - x1)
    
set yHeight to (y2 - y1)
    
set a1Rect to {origin:{x:x1, y:y1}, |size|:{width:xWidth, height:yHeight}}
    
return a1Rect
  on error
    return missing value
  end try
end makeNSRect

★Click Here to Open This Script 

2017/06/22 指定矩形内に含まれるデータをリストで返す v2

指定矩形座標内に指定座標が含まれるかどうかを判定するAppleScriptです。

以前に掲載したPure AppleScript版から改修してCocoaの機能で書き直してみました。ただ、これで正しいのかどーかというのはいまひとつ確証がありません。

width=0, height=0のRectを作ってオーバーラップのチェックをしてみましたが、これではオーバーラップの検出ができなかったためにwidth=1, height=1にしてみました。

→ やっぱり計算内容に納得が行かなかったので作った改修版(v3)はこちら

AppleScript名:指定矩形内に含まれるデータをリストで返す v2
– Created 2017-06-22 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4701

set aList to {{507, 162}, {338, 166}, {389, 166}, {448, 166}, {286, 110}, {504, 109}, {558, 108}, {341, 113}, {394, 115}, {447, 112}, {234, 107}, {611, 110}, {286, 58}, {501, 63}, {556, 58}, {337, 59}, {391, 60}, {448, 63}, {611, 58}}

set rangeList to {{500, 100}, {550, 180}} –{{x1,y1}, {x2,y2}}
set resList to withinRange(rangeList, aList) of me
–>  {{507, 162}, {504, 109}}

on withinRange(rangeList, targetList)
  set aRect to makeNSRect(rangeList) of me
  
  
set includedList to {}
  
repeat with i in targetList
    set bRect to makeNSRectFromXY(i) of me
    
if bRect = missing value then error “Missing Data”
    
set aRes to detectRectanglesCollision(aRect, bRect) of me
    
if aRes = true then
      set the end of includedList to contents of i
    end if
  end repeat
  
  
return includedList
end withinRange

on makeNSRectFromXY(bList as list)
  try
    copy bList to {x, y}
    
set xWidth to 1
    
set yHeight to 1
    
set a1Rect to {origin:{x:x, y:y}, |size|:{width:xWidth, height:yHeight}}
    
return a1Rect
  on error
    return missing value
  end try
end makeNSRectFromXY

on makeNSRect(aList as list)
  try
    copy aList to {{x1, y1}, {x2, y2}}
    
set xWidth to (x2 - x1)
    
set yHeight to (y2 - y1)
    
set a1Rect to {origin:{x:x1, y:y1}, |size|:{width:xWidth, height:yHeight}}
    
return a1Rect
  on error
    return missing value
  end try
end makeNSRect

–NSRect同士の衝突判定
on detectRectanglesCollision(aRect, bRect)
  set a1Res to current application’s NSIntersectionRect(aRect, bRect)
  
return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}})
end detectRectanglesCollision

★Click Here to Open This Script 

2017/03/07 矩形座標同士の合計

NSUnionRectによる矩形座標(NSRect)の合計をためしてみました。

unionrect.png

実際に方眼紙を塗りつぶしてみると、計算結果が不思議な感じもするのですが(空いているセルもあるので)、、、そういうものなんでしょう、、、か(^ー^;;;;;

AppleScript名:矩形座標同士の合計
– Created 2017-03-06 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4515

set a1Rect to {origin:{x:10, y:10}, |size|:{width:40, height:40}}
set b1Rect to {origin:{x:30, y:30}, |size|:{width:40, height:40}}
set a1Res to current application’s NSUnionRect(a1Rect, b1Rect)
–>  {origin:{x:10.0, y:10.0}, size:{width:60.0, height:60.0}}

★Click Here to Open This Script 

2017/03/06 矩形座標同士の衝突判定 v3

なんとなくあるとは予想していた矩形座標(NSRect)同士の衝突検出。Cocoa勉強会池袋で聞いてみたら、やっぱりありました(汗)

面倒な処理も必要なく、NSIntersectionRect(aRect, bRect) で重なり合う(and)箇所を検出できてしまいました。1対の矩形座標の衝突検出で所要時間0.001秒以下。たいへん簡単かつお手軽に検出できました。

NSIntersectionRectとNSUnionRectのことは、しばらく忘れられないことでしょう。

AppleScript名:矩形座標同士の衝突判定 v3
– Created 2017-03-06 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4514

set a1Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b1Rect to {origin:{x:30, y:30}, |size|:{width:100, height:100}}
set a1Res to detectRectanglesCollision(a1Rect, b1Rect) of me
–>  true

set a4Rect to {origin:{x:0, y:20}, |size|:{width:100, height:10}}
set b4Rect to {origin:{x:1000, y:10000}, |size|:{width:50, height:100}}
set a2Res to detectRectanglesCollision(a4Rect, b4Rect) of me
–>  false

set a3Rect to {origin:{x:30, y:30}, |size|:{width:50, height:50}}
set b3Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set a3Res to detectRectanglesCollision(a3Rect, b3Rect) of me
–> true

set a4Rect to {origin:{x:0, y:20}, |size|:{width:100, height:10}}
set b4Rect to {origin:{x:10, y:10}, |size|:{width:50, height:100}}
set a4Res to detectRectanglesCollision(a4Rect, b4Rect) of me
–> true

–NSRect同士の衝突判定
on detectRectanglesCollision(aRect, bRect)
  set a1Res to current application’s NSIntersectionRect(aRect, bRect)
  
return not (a1Res = {origin:{x:0.0, y:0.0}, |size|:{width:0.0, height:0.0}})
end detectRectanglesCollision

★Click Here to Open This Script 

2017/03/05 矩形座標同士の衝突判定 v2

2つのNSRect同士の衝突判定を行うAppleScriptです。v1ではNSRectの内含の順序が異なると衝突を検出できないので修正しました。

→ 矩形座標同士の衝突判定 v3

rect2_resized.png

Rect AがRect Bを含むかどうかチェックを行うというのがV1の処理内容で、これはRect AがRect Bよりも大きいことを前提としたもの。Rect Bのほうが大きい場合には成立しません。

そこで、Rect A>Rect Bを前提とした処理を行なったあとで、衝突していない(false)と判定した場合には、Rect AとRect Bを入れ替えて再度処理してみました。最悪の場合、かなりの回数のループを行なってしまうわけですが、他にいろいろ解決策はありそうです。

救いがあるのは、数百回程度のループ処理ならさほど時間がかからないというところでしょうか。1対の矩形の衝突判定で0.01秒程度。座標のステップ値を10に設定したときには0.002秒程度でした。

AppleScript名:矩形座標同士の衝突判定 v2
– Created 2017-03-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4510

set a1Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b1Rect to {origin:{x:30, y:30}, |size|:{width:100, height:100}}
set a1Res to detectCollision(a1Rect, b1Rect, 1) of me
–> true

set a2Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b2Rect to {origin:{x:200, y:30}, |size|:{width:100, height:100}}
set a2Res to detectCollision(a2Rect, b2Rect, 1) of me
–> false

set a3Rect to {origin:{x:30, y:30}, |size|:{width:50, height:50}}
set b3Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set a3Res to detectCollision(a3Rect, b3Rect, 1) of me
–> true

set a4Rect to {origin:{x:0, y:20}, |size|:{width:100, height:10}}
set b4Rect to {origin:{x:10, y:10}, |size|:{width:50, height:100}}
set a4Res to detectCollision(a4Rect, b4Rect, 1) of me
–> true

–NSRect同士の衝突判定
on detectCollision(aRect, bRect, stepNum)
  set a1Res to detectCollisionSub(aRect, bRect, stepNum) of me
  
if a1Res = true then
    return true
  else
    set a2Res to detectCollisionSub(bRect, aRect, stepNum) of me
    
return a2Res
  end if
end detectCollision

on detectCollisionSub(aRect, bRect, stepNum)
  
  
set origX1 to aRect’s origin’s x
  
set origY1 to aRect’s origin’s y
  
set origX2 to origX1 + (aRect’s |size|’s width)
  
set origY2 to origY1 + (aRect’s |size|’s height)
  
  
repeat with i from origX1 to origX2 by stepNum
    set aPoint to {x:i, y:origY1}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origY1 to origY2 by stepNum
    set aPoint to {x:origX2, y:i}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origX1 to origX2 by stepNum
    set aPoint to {x:i, y:origY2}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origY1 to origY2 by stepNum
    set aPoint to {x:origX1, y:i}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
return false
end detectCollisionSub

★Click Here to Open This Script 

2017/03/05 矩形座標同士の衝突判定

2つのNSRect同士の衝突判定を行うAppleScriptです。

→ 矩形座標同士の衝突判定 v3

NSRect(矩形)とNSPoint(点)の間で矩形に座標が含まれるかどうか確認を行うのには、NSPointInRectを利用することになりますが、Referenceを見てもNSRect(矩形)同士が重なっているかどうかを確認するメソッドが存在しないようです。

矩形同士の衝突判定を行う仕組みといえばSpriteが存在しているため、SpriteKitの機能を使えば簡単にできそうですが、そこまで手をかけなくても、ただ単にNSRect(矩形)の外周部を1刻みでNSPoint(点)に分解し、すべてのNSPoint(点)が相手側のNSPoint(矩形)に含まれるかをループでチェックすればわかります(知性のカケラもない処理です)。

rect1_resized.png

大きな矩形同士であれば、ステップ数を大きくするなどのチューニングも必要かもしれませんが、ほかにもっといい手段がありそうな気もします。

AppleScript名:矩形座標同士の衝突判定
– Created 2017-03-05 by Takaaki Naganoya
– 2017 Piyomaru Software
use AppleScript version “2.4″
use scripting additions
use framework “Foundation”
–http://piyocast.com/as/archives/4508

set a1Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b1Rect to {origin:{x:30, y:30}, |size|:{width:100, height:100}}
set a1Res to detectCollisionDetect(a1Rect, b1Rect, 1) of me
–> true

set a2Rect to {origin:{x:10, y:10}, |size|:{width:100, height:100}}
set b2Rect to {origin:{x:200, y:30}, |size|:{width:100, height:100}}
set a2Res to detectCollisionDetect(a2Rect, b2Rect, 1) of me
–> false

–NSRect同士の衝突判定
on detectCollisionDetect(aRect, bRect, stepNum)
  
  
set origX1 to aRect’s origin’s x
  
set origY1 to aRect’s origin’s y
  
set origX2 to origX1 + (aRect’s |size|’s width)
  
set origY2 to origY1 + (aRect’s |size|’s height)
  
  
repeat with i from origX1 to origX2 by stepNum
    set aPoint to {x:i, y:origY1}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origY1 to origY2 by stepNum
    set aPoint to {x:origX2, y:i}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origX1 to origX2 by stepNum
    set aPoint to {x:i, y:origY2}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
repeat with i from origY1 to origY2 by stepNum
    set aPoint to {x:origX1, y:i}
    
set aRes to current application’s NSPointInRect(aPoint, bRect)
    
if aRes = true then return true
  end repeat
  
  
return false
end detectCollisionDetect

★Click Here to Open This Script