グループ化された図形の位置・大きさの扱い

実装にクリティカルに響いてこない箇所はオープンな場所にメモする事にしてみる.いきなりこれだけ書いても意味不明ですが,ある程度メモが溜まったら目次でも作ります.

Microsoft PowerPoint では「複数の図形のグループ化」と言う機能がありますが,この機能を使用すると OpenXML ファイルに と言うタグが現れます.この場合,グループに属する各図形はこの の子要素()として格納されており,ほとんどの要素はグループ化されていない場合(直に タグが出現する場合)と同様に解析していけば良いのですが,x, y 座標,横幅,回転角度などの扱いが問題となります.

Standard ECMA-376 の該当箇所を読んでみましたが,「グループの各要素に影響を与える」程度の記述しかなく具体的にどう計算すれば良いのかがはっきりと分らなかったので,実際にサンプルファイルを作ってテストしてみることにしました.

20.5.2.17 grpSp (Group Shape)

This element specifies a group shape that represents many shapes grouped together. This shape is to be treated just as if it were a regular shape but instead of being described by a single geometry it is made up of all the shape geometries encompassed within it. Within a group shape each of the shapes that make up the group are specified just as they normally would. The idea behind grouping elements however is that a single transform can apply to many shapes at the same time.
・・・(中略)・・・
In the above example we see three shapes specified within a single group. These three shapes have their position and sizes specified just as they normally would within the shape tree. The generating application should apply the transformation after the bounding box for the group shape has been calculated.

Standard ECMA-376

サンプルファイル: group_test.pptx

問題の箇所だけ以下に抜き出してみます.これを見ると,, , および子要素の( タグの)x, y 座標,大きさは全て同じことが分かります.したがって,それぞれの図形の実際の描画位置,描画サイズを求めるには , , の差を子要素のそれぞれの図形()に反映させる必要があることも分かります.

下の例から,座標に関しては「 + (<子要素の a:off> - ) * ( / )」,大きさに関しては「<子要素の a:ext> * ( / )」と言う変換を行うことで,実際の描画座標,大きさを導出できる事が予想できます.また,rot のような属性がある場合には,その値を全ての子要素に適用するようです(ちなみに,rot の値は実際の角度を 60 * 1,000 倍した値になります.すなわち,rot="2804799" は,46.74665度を表します).

大体,当初予想していた通りだったのですが, の存在で少し混乱しました. の x, y 座標の位置を基点として表せば () 良いんじゃないかなぁと思っていたので.これは,グループ化やグループ化解除の際に,対象となる全ての図形の座標・大きさをイチイチ再計算しなくて良いように,と言う事なのでしょう.

<p:grpSp>
+ <p:nvGrpSpPr>
  <p:grpSpPr>
    <a:xfrm>
      <a:off x="500034" y="500042" /> 
      <a:ext cx="2357454" cy="1357322" /> 
      <a:chOff x="500034" y="500042" /> 
      <a:chExt cx="2357454" cy="1357322" /> 
    </a:xfrm>
  </p:grpSpPr>
  <p:sp>
    ...
    <p:spPr>
      <a:xfrm>
        <a:off x="500034" y="500042" /> 
        <a:ext cx="2357454" cy="1357322" /> 
      </a:xfrm>
    ...
  </p:sp>
  ...
</p:grpSp>

<p:grpSp>
+ <p:nvGrpSpPr>
  <p:grpSpPr>
    <a:xfrm>
      <a:off x="500034" y="3643314" /> 
      <a:ext cx="3786214" cy="2786082" /> 
      <a:chOff x="500034" y="500042" /> 
      <a:chExt cx="2357454" cy="1357322" /> 
    </a:xfrm>
  </p:grpSpPr>
  <p:sp>
    ...
    <p:spPr>
      <a:xfrm>
        <a:off x="500034" y="500042" /> 
        <a:ext cx="2357454" cy="1357322" /> 
      </a:xfrm>
    ...
  </p:sp>
  ...
</p:grpSp>

<p:grpSp>
+ <p:nvGrpSpPr>
  <p:grpSpPr>
    <a:xfrm rot="2804799">
      <a:off x="6124017" y="4573944" /> 
      <a:ext cx="2357454" cy="1357322" /> 
      <a:chOff x="500034" y="500042" /> 
      <a:chExt cx="2357454" cy="1357322" /> 
    </a:xfrm>
  </p:grpSpPr>
  <p:sp>
    ...
    <p:spPr>
      <a:xfrm>
        <a:off x="500034" y="500042" /> 
        <a:ext cx="2357454" cy="1357322" /> 
      </a:xfrm>
    ...
  </p:sp>
  ...
</p:grpSp>