Java Drawing DrawTop

Language

JP  US  UK

 

図形の移動/リサイズ

 H. Jyounishi, Tokyo Japan
 

Frame (Index), No frame                 version:0.3(latest)  

要旨:図形を選択しその選択ボックスをマウスでドラッグするとその図形が移動する。図形のリサイズハンドルをドラッグすると、図形のサイズを変えられる(リサイズ)。この2つの機能は一般のドローツール(図形作成・描画ツール)と同様である。これら機能ではマウスが動くたびに図形の移動(Move)、リサイズ(Resize)コマンドを作成し、コマンドディスパッチャー(ExecCommand)に渡して処理を依頼する。マウスの動きを受け取って図形を移動/リサイズを制御するのがこのページで説明するMoveResizeShapeLSクラスで、実際に図形を移動/リサイズするのは図形要素のメソッド(ShapeElementのmove/resizeメソッド)である。

このページで説明するクラス: MoveResizeShapeLS(API), AutoAlign(API), Align, AlignedCouple


1. 概要
1.1 カーソルマーク

図1.1はカーソルマークを示す。 マウスを選択ボックス(selection box)、リサイズハンドル(resize handles)上においたとき、 それに対応するカーソルマークを表示する。このアプリケーションでは、 直線、開いた折れ線、開いた三次曲線の端点にマウスを置くと、クロスヘアーカーソルを表示する(図(b)、(c))。 そしてクロスヘアーカーソルで端点をドラッグすると、端点を移動することができる(図1.2(a)1.3)。


図 (a)
Cursor marks:

図 (b)

図 (c)
図1.1 選択ボックス, リサイズハンドル, カーソルマーク

1.2 図形の移動、リサイズ戻る=>page top
直線

直線の場合、選択ボックスは表示されないので、直線部分をマウスドラッグで平行移動する(図1.2(a))。 端点(太線四角マーク)を移動すれば方向と長さを変える(リサイズ)ことができる(図1.2 (b))。
 

PolyLine(折れ線)

閉じていない折れ線が選択されると図2右図のように表示される。閉図形と同様に選択ボックスとリサイズハンドルが表示され、閉図形と同様に操作できる。

これとは別に、端点に太線の四角マークが表示され、これをマウスドラッグで動かすと図3のように端点が移動する。動かす端点を含む線分の方向は変化せずに長さを変える端点移動である。 これは図形どうしをつなぐコネクターのリサイズに便利で、水平線分、垂直線分に対して有効である。

但し斜めの線分に対する端点移動は、あまり直感的とは言えない(図4)。
以降、適切な言葉がないので、端点移動の太線の四角マークを端点移動ハンドルと呼ぶことにする。


移動カーソル(move cursor)で平行移動

クロスヘアーカーソルで端点を移動

図1.2(a) 直線の移動、リサイズ



移動カーソル(move cursor)で平行移動

クロスヘアーカーソルで端点を移動

図1.2(b) 折れ線の移動、リサイズ



元の折れ線

クロスヘアーカーソルで端点を右へ移動

クロスヘアーカーソルで端点を左へ移動

クロスヘアーカーソルで端点を上へ移動
図1.2(c) 折れ線の端点を色々な方向へ移動


NEリサイズハンドルをドラッグ

Nリサイズハンドルをドラッグ
図1.2(d) 閉じた図形のリサイズ.

1.3 Shift/Ctrl/Alt キーを押しながらマウスをドラッグした場合 戻る=>page top

操作

説明

選択ボックスでの移動

Shift/Ctrlキーを押していると、強制的に水平、垂直方向にのみ移動される。
コネクター(直線/折れ線)の端点が他の図形に接続している場合、 Ctrl/Shiftキーを押しながらコネクター(直線/折れを移動すると、コ ネクターが接続しているその図形の境界をガイドラインとしてコネクターが動く(図1.3)。

直線、折れ線の端点の移動

Shift/Ctrlキーを押していると、水平、垂直方向の移動のみ許される。

リサイズ

ShiftキーまたはCtrlキーを押しながらリサイズハンドルをドラッグすると、縦横比を変えずにサイズできる。 またAltキーを押しながらドラッグすると、正方形にフィットするようにリサイズできる。


Ctrl/Shiftキーを押したまま、
縦線を右側に動かす。

縦線はガイド曲線に沿って動き、
接続関係は (赤マークが接続点) 保持される
&

図1.3 Ctrl /Shiftキーの効果(ガイドラインに沿って移動)



1.4 Auto align 戻る=>page top

この機能は図形の整列コマンドalign_left, align_center, align_right. align_top, align_middle, align_bottomと同じ機能を、図形を移動、リサイズしたときに実行することができる。

図(a)は整列していないブロックダイアグラムである。

図1.4(a)整列していないブロックダイアグラム


まず左のKeyboardボックスを選択して上に動かす。KeyTypedボックスとある誤差範囲で水平に並ぶと下図のように赤い点線が表示される。この場合、大きさが同じボックスなので、align_top, align_middle, align_bottomの条件が同時に満たされ、赤い点線が3本表示される。この時点でマウスボタンを離すと、正確にKeyboardボックスはKeyTypedボックスに整列する。もう一度選択ボックス(周りの灰色に枠)の上でマウスボタンを押すと、赤い点線が表示されるので、正確に並んでいることが確認できる。

図1.4(b) Keyboardボックスを上に移動


次にKeyTypedボックスを少し左へ動かすと、Keyboardボックスとは水平方向に並び、かつListenerPanelボックスとは垂直方向に整列し、図(c)のように整列を表す赤い点線が表示される。この時点でマウスボタンを離すと、KeyboardボックスおよびListenerPanelボックスと整列させることができる。

図1.4(c) Keytypedボックスを左に移動


以下同様な操作を繰り返し図(d)を得る。

図1.4(d) 完成したブロックダイアグラム



2. Class MoveResizeShapeLS 戻る=>page top
public class MoveResizeShapeLS implements MouseListener, MouseMotionListener

MoveResizeShapeLSは図形の移動/リサイズの他につぎの機能の起動・制御も行う。

(1)コネクター(2つの図形をつなぐ線) See=>2.1 (1)
直線、折れ線の端点をマウスドラッグで他の図形(ターゲット図形)に近づけてマウスボタンを離すと、 直線、折れ線をコネクターとしてターゲット図形の境界線上の任意の点に接続する。

(2)コネクターとの接続保持 See=> 2.1 (2)
図形を移動/リサイズするとき、その図形に接続するコネクターの端点を動かし接続を保持する。

(3)Auto align(AutoAlignクラス) See=> AutoAlign
図形をマウスドラッグで移動/リサイズしている最中に隣の図形とある誤差範囲で整列したら、点線で整列状況を表示する。 この点線が表示されている間にマウスボタンを離すと、図形を少し移動/リサイズし誤差ゼロで隣の図形に整列させる。 この機能はAlign_left, Align_center, Align_right, Align_top, Align_Middle, Align_bottomコマンドを 図形の移動/リサイズ中に実行するもので、ブロック図などの作成には大層便利である。

2.1 制御の流れ

図形の移動/リサイズを行うためにマウスの動きを受け取るマウスリスナーが MoveResizeShapeLS(LSはListenerの略)である。
2.1 制御の流れ (1)図形の移動/リサイズ処理の起動・終了
移動/リサイズ対象の図形に対する処理ステップを説明する。

処理ステップ

説明

Step1. 起動

マウスボタンを押したとき、SelectionLS (図形選択クラス)のmousePressedメソッドが呼ばれる。 マウス位置が選択ボックスまたはリサイズハンドル上にあることが確認できれば(注)、move/resizeコマンドと判断しSelectionLSの prepareMoveResizeCommandメソッドを呼ぶ。

(注)マウスが図形上にあるか、選択ボックスまたはリサイズハンドル上にあるかなどは、 MousePositionLSで常に計算している。

Step2. コマンド発行

prepareMoveResizeCommandで マウスが選択ボックス(または図形内部)上にあればmoveコマンド、リサイズハンドル上にあればresizeコマンドと判断し、 標準的なコマンド列を作成してコマンドディスパッチャーExecCommandを呼ぶ。

Step3. コマンド分岐

ExecCommandでコマンドを分岐させ、このクラスのstartメソッドを呼びだしてMoveResizeShapeLSを起動する。

Step4. マウスリスナー
設定、初期設定

MoveResizeShapeLSのstartメソッドでマウスリスナー(MoveResizeShapeLS自身)をListenerPanelにセットする。これで制御がマウスリスナーであるMoveResizeShapeLSに移りマウスイベントが起きるまで待機状態に入る。

リサイズ前の図形をundoManagerに設定。これはContainerManagerのundoサポート機能を使う。

Step5. move/resize
処理開始・実行

マウスドラッグをが始まると、 MoveResizeShapeLS.mouseDraggedメソッドでマウスの動きを取得し図形要素の resizeメソッドを呼ぶ (図形のmoveはresizeメソッドで位置だけを変更する場合に相当する)。
マウスが端点移動ハンドル上にあるときは、図形要素の moveEndPointメソッドを呼ぶ。
参照=>ShapeElementのmove/resizeメソッド(このページ)

Step6. 後処理

MoveResizeShapeLSのmouseReleasedが呼ばれると、endメソッドを呼んで終了処理。

リサイズ後の図形をundoManagerに設定 =>ContainerManagerのundoサポート機能



(2)コネクターをターゲット図形に接続する処理

移動/リサイズされる図形がコネクターの場合、次の処理を行う。

処理ステップ

説明

Step1. 接続候補点の表示

コネクター端点を移動しコネクター端点が他の図形(ターゲット図形)に近づいたとき、その図形の境界上に接続候補点を表示する。MoveResizeShapeLSのmouseDraggedメソッドから、ConnectionLSdrawMouseHitPTメソッドを呼んで接続候補点を表示する。
See=> 図 2.1, 2.2

Step2. コネクターをターゲット図形に接続

drawMouseHitPTメソッドから接続点が戻れば、 ShapeElement.moveEndPointメソッドで コネクターの端点を接続点に移動する。 接続点は高精度に計算されるので、コネクターの端点をターゲット図形上に計算機誤差の範囲で載せる。


See: 詳細 => Connector, ConnectionLS

図2.1 コネクターを図形境界に接続

図2.2 コネクターを図形のコーナ点 (端点/接続点) に接続


(3)コネクターの接続を保持する処理

移動/リサイズされるターゲット図形に接続するコネクターがあれば、コネクターをリサイズまたは変形して接続を保持する。 またターゲット図形がグループ図形の場合、 グループの子要素に接続するコネクターも接続を保持するためにリサイズする必要がある。 このようにコネクターに関する処理はかなり厄介である。

=> ConnectionUtil

処理ステップ

説明

Step1. 初期設定

この処理はMoveResizeShapeLSのstartメソッドから ConnectionUtil.setTargetsメソッド を呼んで、移動/リサイズされる図形とそれに接続するコネクターの一覧を作成する。

Step2. コネクターのリサイズ

MoveResizeShapeLSのmouseDraggedメソッドから ConnectionUtil.resizeConnectorsメソッド を呼んで、コネクターのリサイズ(変形)を行いターゲット図形との接続を保持する。

Step3. 後処理

MoveResizeShapeLSのmouseReleasedメソッドからConnectionUtil.endメソッドを呼んで終了処理を行う。


 


(a) 元の図形

(b) "keyboad" ボックスを左へ移動

(c) "keyTyped"ボックスを下へ移動.

(d) "InputMethodTextChanged" "keyTyped" ボックスを上へ移動
図 2.3 接続関係の保持
カラーマークは動かされる図形に接続するコネクターとの接続点。
コネクターにさらにコネクターが接続する場合、その接続点は色を変えて表示。


2.2 MoveResizeShapeLS API 戻る=>page top

フィールド

説明

mousePositionInfo

private MousePositionInfo mousePositionInfo

マウスで選択ボックスまたはリサイズハンドルを押した時のマウス位置情報。

このクラスのstartメソッドの引数で渡される。

selectedContainers

ShapeContainer[] selectedContainers

移動/リサイズされる図形。 グループ図形でも可。 this.startメソッドで設定する。

auto_tracking_option int auto_tracking_option
DrawParameters.CONNECTOR_AUTO_TRACKING_OPTION をこのフィールドに設定

connectionUtil

ConnectionUtil connectionUtil=new ConnectionUtil()

コネクターのリサイズを一括して行うConnectionUtilオブジェクトを設定。 なおConnectionUtilはundoの設定も行う。

autoAlign AutoAlign autoAlign=new AutoAlign(this)
自動整列(auto align)を行うオブジェクトを設定する。
参照=>AutoAlign
mode int mode
移動/リサイズのモードを設定する。
選択ボックス(図1.1)をドラッグして図形を移動するとき: static定数Command.MOVEを設定。
リサイズハンドル(図1.1)をドラッグして図形を移動するとき: static定数Command.RESIZEを設定。
直線、折れ線、三次曲線の端点をドラッグして端点を移動するとき(図3): static定数Command.MOVE_ENDPTを設定。

startPoint

Point2D startPoint:ドラッグ開始点

newPoint

Point2D newPoint:ドラッグ現在点

oldPoint

Point2D oldPoint:一回前に呼ばれた時のドラッグ点

startBox

Rectangle2D startBox:ドラッグ開始時に selectedContainersを全て囲むBoundingBox

newBox

Rectangle2D newBox:現在のselectedContainersを 全て囲むBoundingBox

oldBox

Rectangle2D oldBox:mouseDraggedメソッドが 一回前に呼ばれた時のBoundingBox

workVector Vector workVector
作業用に使うVectorオブジェクト

メソッド

説明

start

public void start(MousePositionInfo info, MouseEvent e)
引数:

info - 選択図形を移動/リサイズするために、 選択図形上でマウスボタンが押されたときのMousePositionInfo データ。 このデータから選択ボックスが押されたのか、リサイズハンドルが押されたのかなどがわかる。

e - SelectionLSのmousePressedメソッドで受け取ったMouseEventオブジェクト。

処理:
ExecCommandでMoveResizeShapeLSオブジェクトを作成した後にこのメソッドを呼が呼ばれる。

・MoveResizeShapeLSをマウスリスナーとして、ListenerPanelに設定する。

これと同時にSelectionLS(図形選択クラス)を一時停止する。

initメソッドを呼ぶ。

このクラスでは、MouseListenerインターフェイスのmousePressedメソッドは呼ばれない。 マウスで選択ボックスまたはリサイズハンドルを押した時のマウスイベントはSelectionLSのmousePressedメソッドが受け取ってしまうからである。 このクラスのmousePressedを呼ぶ代わりにinitメソッドを呼ぶ。

ContainerManager.undoSetupStartを呼んで 図形変更前の図形、コネクターを設定する。

init

public void init(MouseEvent e)
引数はstartメソッドと同じ。
・引数mousePositionInfoをチェックしてmodeを設定する。
選択図形をフィールド変数selectedContainersに設定する。

modeが端点移動(MOVE_ENDPT)の場合、直線、閉じていない折れ線、曲線だけが許されるので isSuitableForMoveEndPTでチェックして設定する。

・フィールド変数startBoxes, oldBoxes, newBoxesなどの設定を行う。
・ドラッグ開始点をフィールド変数startPointに設定。
・選択図形の図形要素のメソッドmouseStartを呼んで 図形要素変更の初期設定を行う。

これは端点移動ハンドルをドラッグする場合に必須であり、 始点、終点のどちらを動かすかなどを決定する。

AUTO_ALIGNの設定を行うため、 AutoAlign.startメソッドを呼ぶ。

・Connector関係の処理(2.1 (2), 2.1 (3))を行うため ConnectionUtil.startメソッドを呼ぶ。

end

public void end()

・MoveResizeShapeLSを、ListenerPanelから削除する。

SelectionLS(図形選択クラス)を再開する。

・ConnectionUtilに移動・リサイズ後の図形を設定する。

isSuitableFor
MoveEndPT
public boolean isSuitableForMoveEndPT(ShapeContainer container)
端点を移動するのに適切な図形か否かを判定する。直線、閉じていない折れ線、曲線ならばOK。

mousePressed

public void mousePressed(MouseEvent e)

・このメソッドは呼ばれないので何もしない。

mouseDragged

public void mouseDragged(MouseEvent e)

・Sift/Ctrl keyを押している場合

moveの方向は、水平/垂直方向に限定する。
基本閉図形のリサイズは縦横比を1にする。

・フィールド変数modeの値により所定のメソッドを呼ぶ。これは結構複雑かつ重要である。

・mode=Command.MOVING_MODEのとき

ShapeElement.moveメソッドを呼ぶ。

・mode=Command.RESIZING_MODEのとき

ShapeElement.resizeメソッドを呼ぶ。

・mode=Command.MOVING_ENDPT_MODEのとき

ShapeElement.moveEndPointメソッドを呼ぶ。

・Auto_Align, Connector処理のためAutoAlign.mouseDragged, ConnectionUtil.mouseDraggedを呼ぶ

mouseReleased

public void mouseReleased(MouseEvent e)

・Auto_Align, Connector処理のためAutoAlign.mouseReleased, ConnectionUtil.mouseReleasedを呼ぶ

mouseMoved

public void mouseMoved(MouseEvent e)

・なにもしない

mouseClicked

public void mouseClicked(MouseEvent e)

・なにもしない

mouseEntered

public void mouseEntered(MouseEvent e)

・なにもしない

mouseExited

public void mouseExited(MouseEvent e)

・なにもしない



: ShapeElementのmove/resizeメソッド

マウス位置情報(MousePositionInfo)を見て、MoveかResizeかを判定し、図形要素 (ShapeElement)の対応するメソッドを呼ぶ。

Move操作は位置だけを変更するResize操作の一種なので、呼び出すメソッドはresizeメソッド

Move

マウス位置が、SELECTION_FRAME, SHAPE_BOUNDARY, INSIDE_SHAPEなどのの場合で、 リサイズハンドル上にないとき。=> 図形移動のため、 ShapeElementresizeメソッド(*1)を呼ぶ。

Resize

マウス位置がリサイズハンドル上(NW_RESIZE - W_RESIZE)または直線、折れ線の端点(END_POINT)の場合

・リサイズハンドル上にあるとき

=> ShapeElementのresizeメソッド(*1)を呼ぶ。

・端点上にあるとき

=> ShapeElementのmoveEndPointメソッド(*2)を呼ぶ。


(*1) resize(Rectangle2D oldBox, Rectangle2D newBox)

基本閉図形のmove、resizeメソッド。oldBoxからnewBoxにフィットするように図形を相似変換する。 oldBoxとnewBoxのサイズが同じで、位置だけ変わる場合はmoveになる。

(*2) moveEndPoint(int ctrl, int movingPoint, Point2D draggStartPoint, Point2D oldPoint, Point2D newPoint)

直線の端点を掴んでのリサイズは、端点を動かす操作になるのでこのメソッドを使う。

またマウス位置情報が端点(MousePositionInfo.END_POINT)で直線、折れ線の場合は、 コネクター対応のリサイズを行うのでこのメソッドを呼ぶ。



3. AutoAlignクラス 戻る=>page top


3.1 AutoAlignの例

=> Auto align 図1.4(a) - 1.4(d)(このページ), 操作説明書 auto align, auto align 例1 - 例5, 例題-1
この機能は操作説明書の図形の整列コマンド align_left, align_center, align_right. align_top, align_middle, align_bottomと同じ機能を 図形を移動/リサイズしているときにリアルタイムに実行する。選択した図形を移動/リサイズしている最中に、 他の図形と整列すると赤い点線を表示する。 赤い点線が表示されている間に、マウスボタンを離すと計算機誤差範囲で正確に整列させることができる。


3.2 制御方法

Auto align機能はMoveResizeShapeLSクラスからAutoAlignクラスのコンストラクタ、メソッドを呼び出して実行する。

処理ステップ

説明

Step1. 起動

MoveResizeShapeLS.initメソッドからAutoAlign.startメソッドを呼びだして初期設定を行い、 AutoAlign.drawHitAlignsメソッドで整列状況の初期表示を行う。

Step2. 整列状況のチェック・表示

マウスがドラッグされるたびに整列状況のチェック・表示を行う。 このためMoveResizeShapeLS.mouseDraggedメソッドから AutoAlign.mouseDraggedメソッドを呼びだし、 AutoAlign.drawHitAlignsメソッドで整列状況を表示する。

Step3. 整列実行

マウスボタンを離したときに、移動またはリサイズされている図形が 隣の図形とある誤差範囲で整列していれば、誤差のないように正確に整列する。 これはMoveResizeShapeLS.mouseReleasedメソッドから AutoAlign.mouseReleasedメソッドを呼び、 さらにAutoAlign.ajustAlignmentメソッドを呼んで正確に整列する。
=> コネクターとの接続は保証される(Figure 3.4)

: もし図1.3, 図2.1, 2.2に示すようなコネクターの接続がなされた場合にはこの処理はスキップされる。 コネクターの接続のほうが優先度が高い。



3.3 処理概要

処理ステップ

説明

Step1. x軸、y軸の目盛り作成

このステップは制御方法のStep1で行う処理である。
MoveResizeShapeLSで移動/リサイズ対象図形を除く全ての表示中の図形からx軸、y軸の目盛り作成する。 この目盛りはAlignオブジェクトで表し、x軸目盛はAlign.XALIGN、 y軸目盛はAlign.YALIGNで区別し、 それぞれxAlignList(ArrayList)yAlignList(ArrayList)に登録する。 xAlignList、yAlignListは目盛りが小さな順に並ぶようにする。
ひとつの図形から目盛りは6個作成する。xAlignListに登録するのはAlign.LEFT、Align.CENTER、Align.RIGHTの3種、 yAlignListに登録するのはAlign.TOP、Align.MIDDLE、Align.BOTTOMの3種である。 これらの目盛りは図形を覆うboundingBoxから作成する。
(注) Align.ENDPTのAlignオブジェクトはxAlignList、yAlignListに登録しない。 つまり目盛りとして採用しない。
以上の処理はAutoAlignクラスのcreateAlignメソッドで行う。

Step2. 整列チェック

このステップは制御方法のStep1整列状況の初期表示と Step2で行う処理である。
移動/リサイズ対象図形の左右上下(Align.LEFT, RIGHT, TOP, BOTTOM)および水平, 垂直中心(Align.CENTER, MIDDLE)が、 上記xAlignListyAlignListの 目盛り(Alignオブジェクト)とある誤差範囲で一致するもの(hitAlign)を選ぶ。
hitAlignが見つかれば、 移動/リサイズ対象図形のAlign(targetAlign)オブジェクトを作成し、 hitAlignと組にしてAlignedCoupleオブジェクトを作成し hitAlignedCouples(Vector配列)に格納する。
これはAutoAlignクラスのcreateHitAlignedCouplesメソッドで実行する。
整列チェックの規則
(1)複数図形を選択して移動/リサイズ対象図形できるが、 表示が煩雑になるためマウスがヒットしている図形に対してだけ整列チェックと表示を行う。
(2)直線、閉じていない折れ線、曲線の端点を移動する場合、作成するAlignオブジェクトはAlign.ENDPTで、 始点、終点のどちらの端点を動かしているかのindex(endPTindex)を持たせる。

Step3. 整列状況の表示

図(b),(c)

このステップは制御方法のStep1整列状況の初期表示と Step2で行う処理である。
移動/リサイズ対象図形のAlignオブジェクト(targetAlign)と xAlignListyAlignListから選ばれた Alignオブジェクト(hitAlign) の組(AlignedCouple)がhitAlignedCouples(Vector配列)に格納されている。
図形がすでに数多く整列している場合、移動/リサイズ対象図形(targetAlign)の Alignオブジェクトにヒットする目盛り側のAlignオブジェクト((hittAlign))が多数見つかっているケースがある。 この場合、赤い点線が多数表示され非常に見ずらいので、Align.LEFT~Align.BOTTOMごとにターゲットに近い hitAlignオブジェクトを1個ないし2個を選んで表示する。これはターゲットの隣の図形との整列を優先するということで直感にもあっている。
hitAlignオブジェクトを1個ないし2個を選択する処理は、AutoAlign.selectHitAlignedCoupleメソッドで実行し、 結果はselectedHitAlignedCouples(Vector配列)に格納する。

: 赤い点線の表示
ターゲット図形とhitAlignの元の図形が矩形や楕円など単純な図形ならば、点線を描画する範囲は簡単に決まる。下図はAlign.TOP、Align.BOTTOMのケースでターゲット図形とhitAlignの元の図形は共に三次曲線である。このとき点線y値は上記の整列チェックで決まっているのでよいが、xの範囲は、Align.TOP、Align.BOTTOMを実現する図形上の点を選んで描画する。あまり精度がいらないので、AlignCouple.setAlignPointsメソッドで曲線から点サンプリングしてAlign.TOP、Align.BOTTOMに最も近い点を選び、xの範囲を決める。点の選択はAlignクラスのgetAlignedPointsで行い、点線の描画はAutoAlignクラスのdrawAlignで行う。

図 (e) Align top 図 (f) Align Bottom

Step4.整列実行

このステップは制御方法Step3で行う処理である。
整列チェックと整列状況の表示はある誤差範囲を前提に実行される。最終ステップでは誤差ゼロで整列させる。 この処理はAutoAlignクラスのAutoAlign.ajustAlignmentメソッドで行う。


3.4 AutoAlign API 戻る=>page top
public class AutoAlign
=> [補足] MOVING_ENDPT_MODEの場合の特別処理

フィールド名

説明

mousePositionInfo

MousePositionInfo mousePositionInfo

コンストラクタでMoveResizeShapeLSから渡されたMousePositionInfoを設定する。

selectedContainers

ShapeContainer[] selectedContainers

コンストラクタでMoveResizeShapeLSのフィールド変数selectedContainersが設定される。selectedContainersはmove, resize, move_endPTの対象となる図形である。

auto_tracking_option int auto_tracking_option
DrawParameters.AUTO_TRACKING_OPTION をこのフィールドに設定
moveResizeShapeLS MoveResizeShapeLS moveResizeShapeLS

MoveResizeShapeLSオブジェクト。コンストラクタで設定する。

mode

int mode

コンストラクタでMoveResizeShapeLSのstatic定数MOVE, RESIZE, MOVE_ENDPTのどれかが設定する。

xAlignList

ArrayList xAlignList

このリストはx軸整列の目盛りに相当する。移動/リサイズ対象図形が この目盛りにある誤差範囲で一致すれば整列状況を示す点線を表示する。
画面に表示されている図形からフィールド変数selectedContainers(移動/リサイズ対象図形)の 図形を除外した図形から、x-align(垂直方向)のデータを作成してputAlignメソッドでこのArrayListに登録する。 このArrayListに登録されるデータはAlignオブジェクトである。
See=>処理概要Step1

yAlignList

ArrayList yAlignList

このリストはy軸整列の目盛りに相当する。移動/リサイズ対象図形が この目盛りにある誤差範囲で一致すれば整列状況を示す点線を表示する。
y-align(水平方向)のデータを作成してputAlignメソッドでこのArrayListに登録する。
See=>処理概要Step1

hitAlignedCouples

Vector hitAlignedCouples

マウスドラッグで移動/リサイズ対象図形(ターゲット)が、 xAlignList、yAlignListのどれかのAlignオブジェクト(hitAlign)と整列したときに、ターゲット図形のAlignオブジェクトを作成し、hitAlignオブジェクトを組にしてAlignedCoupleオブジェクトを作成し、 このVector配列に格納する。この処理はcreateHitAlignedCouplesメソッドで実行する。

=>処理概要 Step2

selectedHitAlignedCouples

Vector selectedHitAlignedCouples

ターゲット図形にヒットするxAlignList、yAlignListのAlignオブジェクト(hitAlign)は多数見つかる可能性がある。 表示を見やすくするため、この中からAlign.LEFT~Align.BOTTOMごとにひとつ選び、 drawHitAlignsメソッドでこのVector配列に格納する。 Align.LEFT~Align.BOTTOMごとにhitAlignをひとつ選ぶ処理はselectHitAlignedCoupleで行う。

See=>処理概要 Step3

errorMargin

public static double errorMargin

整列チェックをするときの許容誤差。現在4ピクセルを設定。

color

Color color

整列を示す点線の色。


メソッド

説明

コンストラクタ public AutoAlign(MoveResizeShapeLS moveResizeShapeLS)

コンストラクタ

public AutoAlign(int mode, MousePositionInfo mousePositionInfo, ShapeContainer[] selectedContainers)

start

public void start(int mode, MousePositionInfo mousePositionInfo, ShapeContainer[] selectedContainers)

• Auto_Alignの初期設定を行う。

: このメソッドはMoveResizeShapeLS.initメソッドが複雑になるのを避けるために用意した。このメソッドは MoveResizeShapeLS.init メソッドから呼ばれる。.

mouseDragged public void mouseDragged(MouseEvent e)
drawHitAlignsメソッドを呼ぶ。
: このメソッドは MoveResizeShapeLS.mouseDragged メソッドから呼ばれる。
mouseReleased public void mouseReleased(MouseEvent e)
• mode=Command.MOVING_ENDPT_MODEの場合

ConnectionUtil.connectedフィールドをチェック、 trueでなければAutoAlign.ajustAlignmentメソッドを呼ぶ。

: Command.MOVING_ENDPT_MODE: 直線、折れ線の端点を動かすモード。図3.1-(2)
• mode=Command.MOVING_MODE/RESIZING_MODEの場合

ConnectionUtil.guidedフィールドをチェック, trueでなければこのクラスのajustAlignmentメソッドを呼ぶ。

: このメソッドは MoveResizeShapeLS.mouseReleased メソッドから呼ばれる。

createAlign

private void createAlign()

コンストラクタから呼び出される。次のputAlignメソッドで、 選択図形(selectedContainers) を除く全ての図形のAlignオブジェクトをxAlignList、yAlignListに登録する。

See=>処理概要Step1

putAlign

private void putAlign(int alignAxis, int alignType, double value, ShapeContainer shapeContainer)

引数:

alignAxis - Align.XALIGN/Align.YALIGN

alignType- Align.LEFT/Align.CENTER/Align.RIGHT/Align.TOP/Align.MIDDLE/Align.BOTTOM

value - 整列位置。Align.XALIGNの場合x値、Align.YALIGNの場合y値。

shapeContainer - フィールド変数selectedContainers以外の表示されている図形コンテナ。

処理:

createAlignから呼び出される。alignType=Align.XALIGNならばAlignオブジェクトをxAlignListに、alignAxis=Align.YALIGNならばyAlignListに登録する。

整列位置を示すvalueが小さい順になるように登録する。

drawHitAligns public void drawHitAligns()
処理:
MoveResizeShapeLSのmouseReleased, mouseDraggedメソッドから呼ばれ、 移動/リサイズ対象図形(ターゲット)が隣の図形とある誤差範囲で整列していれば点線を表示する。
次のcreateHitAlignedCouplesメソッドと selectHitAlignedCoupleメソッドで整列チェックを行い、 drawAlignメソッドで点線を表示する。
:
createHitAlignedCouplesメソッドは作成したAlignedCoupleオブジェクトを this.hitAlignedCouples(Vector)に格納し、 selectHitAlignedCoupleメソッドで選ばれた AlignedCoupleオブジェクトは this.selectedHitAlignedCouples(Vector)に格納される。
=>処理概要Step3

createHitAlignedCouples

private void createHitAlignedCouples(ShapeContainer targetContainer, int endPTindex)

引数:

targetContainer - マウスドラッグしている図形。

フィールド変数selectedContainersに設定されている図形のどれかに一致する。

endPTindex - mode=Command.MOVE_ENDPTのときに、targetContainerのどちらの端点を動かすかを示す。

endPTindex=0のときは始点、endPTindxe=1のときは終点を動かす。
mode=Command.MOVE/RESIZEのときはendPTindexは無効で何を指定しても良い。

処理:

targetContainerの現在の位置、サイズに対して、 xAlignListyAlignListに登録されているAlignオブジェクトのどれかとある誤差範囲で整列しているか否かをチェックする。
もし一致していればtargetContainerからAlignオブジェクト(targetAlign)を作成し、 xAlignListまたはyAlignListのAlignオブジェクト(hitAlign)を組にしてAlignedCoupleオブジェクトを作成し、 フィールド変数hitAlignedCouples(Vector配列)に格納する。

: this.mode==Command.MOVING_ENDPT_MODEの場合の処理
• このメソッドで作成するtargetAlignalignTypeAlign.ENDPTをセットする。
targetAlignboundingBoxに、 endPTindexが指す端点を覆う幅と高さがゼロの矩形を設定する。

selectMovingEndPT

private int selectMovingEndPT()

コンストラクタから呼ばれる。 mode= Command.MOVE_ENDPTの時に図形(直線、折れ線、曲線)のどちらの端点を動かすかを決定して、戻り値で返す。 0ならば始点、1ならば終点を動かす。

selectHitAlignedCouple

private AlignedCouple selectHitAlignedCouple(int alignType, int dir)
引数:
alignType - Align.alignTypeと同じ。
dir - 0/1.

dir=0ならば、画面上でhitAlignPointtargetAlignPoint左側または上側にあるAlignedCoupleを返す。 dir=1ならば画面上でhitAlignPointが、 targetAlignPoint右側または下側にあるAlignedCoupleを返す。

戻り値:
AlignedCoupleオブジェクト
処理:
drawHitAlignsメソッドから呼ばれる。
alignTypeにはAlign.LEFT/Align.CENTER/Align.RIGHT/Align.TOP/Align.MIDDLE/Align.BOTTOMのどれかを指定する。
フィールド変数hitAlignedCouples(Vector配列)に格納されているAlignedCoupleオブジェクトから、 alignTypeに一致する組をひとつ選ぶ。図形が混雑してくると整列を示す赤い点線が多数表示され煩雑になるので、これを避けるために選択する。
選ぶ基準はAlignedCoupleオブジェクトのtargetAlignhitAlignの図形alignAxisと直交する方向で見て近いものを選ぶ。 つまりがtargetAlignhitAlignがx方向の整列ならば、 y方向上方または下方(dirで指定)でtarget図形に近いhit図形をもつAlignedCoupleオブジェクトを一つ選ぶ。
この処理の距離計算はAlignedCoupleクラスのgetAlignOrthogonalDistanceメソッドで行う。
該当するAlignedCoupleオブジェクトがなければ戻り値としてnullを返す。
See=>処理概要Step3

drawAlign

private void drawAlign(AlignedCouple couple)

引数:
couple - 整列状況を示す赤い点線を表示するAlignedCoupleオブジェクト。
処理:
drawHitAlignsメソッドから呼ばれる。 赤い点線の表示はDrawShapeUtil.drawTempShapeメソッドで行う。

• 通常表示(Figure 3.1)

targetP=couple.getTargetAlignPoint(), hitP=couple.getHitAlignPoint()を参照して赤い点線を描画する直線を作成し表示する。
例えばalignType=Align.LEFTの場合、移動/リサイズ図形をhitPのx座標に整列させる。 このため始終点のx座標はhitPのx座標を使い、始終点のy座標はtargetPとhitPのを使って垂直方向の直線を作成する。

• 境界接触、重なりがある場合の表示(Figure 3.2, Figure 3.3)

ajustAlignment

public void ajustAlignment(int ctrl)
引数:
ctrl - Shift/Ctrlキーを押しながらドラッグすると1 or 2が渡される。 これをShapeElement.moveメソッドに渡す。
処理:
(1)this.mode=Command.MOVING_MODEの場合
Step1. XALIGN, YALIGNに対してそれぞれbestAlignedCoupleを選ぶ。

bestCoupleX=this.getBestAlignedCouple(Align.XALIGN);
bestCoupleY=this.getBestAlignedCouple(Align.YALIGN);

Step2. XALIGN, YALIGN方向整列誤差errorX、errorYを取得。

errorX=bestCoupleX.getAlignedError();
errorY=bestCoupleY.getAlignedError();

Step3. this.selectedContainersをベクトル(errorX, errorY)だけ平行移動する。

this.selectedContainers[i].getElement().move(ctrl, newP, true); 0≦i<this.selectedContainers.length, newP(Point2D.double)は現在点に(errorX, errorY)を加えた点

これで正確に整列する。

(2)this.mode=Command.RESIZING_MODEの場合
リサイズでは(1)より細かい指定が必要になる。 例えばNW Resize Handleを動かしてリサイズする場合だと、 リサイズ図形のTOPとLEFTを動かすのでbestAlignedCoupleは次のように選ぶ。
Step1. XALIGN, YALIGNに対してそれぞれbestAlignedCoupleを選ぶ。

bestCoupleX = this.getBestAlignedCouple(Align.XALIGN, Align.LEFT);
bestCoupleY = this.getBestAlignedCouple(Align.YALIGN, Align.TOP);

Step2. (1)と同じ
Step3. this.selectedContainersをベクトル(errorX, errorY)だけNW Resize Handleを動かしてリサイズする。

this.selectedContainers[i].getElement().mouseStart(ctrl, P0);
this.selectedContainers[i].getElement().resize(ctrl, P1, mousePosition, true);


(3)this.mode=Command.MOVING_ENDPT_MODEの場合
getBestAlignedCoupleの第2引数には、Align.ENDPTを指定する。
Step1. XALIGN, YALIGNに対してそれぞれbestAlignedCoupleを選ぶ。

bestCoupleX = this.getBestAlignedCouple(Align.XALIGN, Align.ENDPT);
bestCoupleY = this.getBestAlignedCouple( Align.YALIGN, Align.ENDPT);

Step2. (1)と同じ
Step3. this.selectedContainersのptIndexが指す端点をベクトル(errorX, errorY)だけ移動する。 基本的には次のコードを実行する。

this.selectedContainers[0].getElement().moveEndPoint(ctrl, ptIndex, newPoint);

: MoveResizeShapeLS.mouseReleasedから呼ばれるのでコネクターとの接続は保証される
=> Figure 3.4

getBestAlignedCouple

private AlignedCouple getBestAlignedCouple(int alignAxis)

引数:
alignAxis - XALIGNまたはYALIGN
戻り値:
AlignedCouple - 選ばれたAlignedCoupleオブジェクト
処理:
フィールド変数のselectedHitAlignedCouples(Vector配列)から 引数alignAxisに一致するAlignedCoupleを取り出す。
該当のAlignedCoupleが複数ある場合、次の優先順位で選択する。

(1)重なり部分があり、区間が最大のAlignedCouple

重なり部分はAlignedCouple.checkIntersectionメソッドで求める。

(2)alignAxis方向の誤差が最も小さいAlignedCouple

alignAxis方向の誤差はAlignedCouple.getAlignedErrorメソッドで求める。

getBestAlignedCouple

private AlignedCouple getBestAlignedCouple(int alignAxis, int targetAlignType)

引数targetAlignTypeを追加することにより、上のgetBestAlignedCoupleより詳細な指定ができる。 引数:
alignAxis - XALIGNまたはYALIGN
targetAlignType - Align.LEFTAlign.ENDPTのいずれか
戻り値:
AlignedCouple - 選ばれたAlignedCoupleオブジェクト
処理:
フィールド変数のselectedHitAlignedCouples(Vector配列)から 引数alignAxis、targetAlignTypeに一致するAlignedCoupleを取り出す。 targetAlignTypeは、couple.targetAlignalignTypeと比較する。
該当のAlignedCoupleが複数ある場合、次の優先順位で選択する。

(1)重なり部分があり、区間が最大のAlignedCouple

重なり部分はAlignedCouple.checkIntersectionメソッドで求める。

(2)alignAxis方向の誤差が最も小さいAlignedCouple

alignAxis方向の誤差はAlignedCouple.getAlignedErrorメソッドで求める。


: [補足] MOVING_ENDPT_MODEの場合の特別処理

メソッド

説明

MoveResizeShapeLS.init

this.selectedContainersには一つの ShapeContainerオブジェクトをセットする。

AutoAlign.mouseDragged

DrawParameters.AUTO_ALIGNがfalseならば何もせずにリターン。

AutoAlign.mouseReleased

DrawParameters.AUTO_ALIGNがfalseならば何もせずにリターン。
MOVING_ENDPT_MODEの場合、 ConnectionUtil.connectedをチェックし、 trueならばajustAlignmentメソッドを呼ばない。
自動整列(AutoAlign)よりは、コネクターの接続関係の保持のほうが優先する。

AutoAlign.createAlign

alignType=Align.ENDPTAlignオブジェクトは作成しない。
つまり直線、折れ線、開曲線などの端点に図形を整列させることはない。

AutoAlign.drawHitAligns

MOVING_ENDPT_MODEの場合、 this.selectedContainersの数は1でなければならない。
もしそうでなければエラーメッセージを出力。

AutoAlign.createHitAlignedCouples

drawHitAlignsから呼ばれる。
• このメソッドで作成するtargetAlignalignTypeAlign.ENDPTをセットする。
targetAlignboundingBoxに、 endPTindexが指す端点を覆う幅と高さがゼロの矩形を設定する。

AutoAlign.ajustAlignment

=> ajustAlignment(3)


4. AutoAlign補助クラス

4.1 Alignクラス 戻る=>page top

フィールド名

説明

alignAxis

int alignAxis

static定数XALIGNまたはYALIGNを設定する。

alignType

int alignType

static定数LEFT/CENTER/RIGHT/TOP/MIDDLE/BOTTOM/ENDPTのどれかを設定する。

value

double value

整列位置を示す値。x-alignの時はx値、y-alignの時はy値。

shapeContainer

ShapeContainer shapeContainer

このオブジェクトの元になる図形(=>ShapeContainer)

endPTindex

int endPTindex

shapeContainerが直線、閉じていない折れ線、曲線のときに、始点、終点のどちらを動かすかを示す。 endPTindex=0のとき始点、endPTindex=1のとき終点。endPTindex=-1は無効を示す。

boundingBox Rectangle2D boundingBox
shapeContainerを覆う矩形。boundingBoxは setBoundingBoxメソッドでセットする。
alignType=ENDPTのときは、フィールド変数endPTindexを参照して、 始点または終点の覆う矩形(幅と高さはゼロ)を返す。
alignedPoints

Point2D[] alignedPoints

フィールド変数alignTypeを実現する点。 setAlignedPointsメソッドでセットする。

XALIGN

static final int XALIGN=10

Alignオブジェクトがx方向整列であることを示す。

YALIGN

static final int YALIGN=11

Alignオブジェクトがy方向整列であることを示す。

LEFT

static final int LEFT=0

Alignオブジェクトがx方向整列で整列位置が図形の左端であることを示す。

CENTER

static final int CENTER=1

Alignオブジェクトがx方向整列で整列位置が図形の中心であることを示す。

RIGHT

static final int RIGHT=2

Alignオブジェクトがx方向整列で整列位置が図形の右端であることを示す。

TOP

static final int TOP=3

Alignオブジェクトがy方向整列で整列位置が図形の上端であることを示す。

MIDDLE

static final int MIDDLE=4

Alignオブジェクトがy方向整列で整列位置が図形の中央であることを示す。

BOTTOM

static final int BOTTOM=5

Alignオブジェクトがy方向整列で整列位置が図形の下端であることを示す。

ENDPT

static final int ENDPT=6

Alignオブジェクトがxまたはy方向整列で整列位置が点であることを示す。

alignString

String[] alignString

整数値XALIGN, YALIGN, LEFT, CENTER, RIGHT, TOP, MIDDLE, BOTTOM, ENDPTの文字列表現


メソッド

説明

コンストラクタ

Align(int alignType, int alignType, double value, ShapeContainer shapeContainer)

引数をフィールド変数に設定する。
setBoundingBox, setAlignedPointsメソッドを呼んでフィールド変数boundingBox, alignedPointsに値をセットする。

コンストラクタ

Align(int alignType, int alignType, double value, ShapeContainer shapeContainer, int endPTindex)

引数をフィールド変数に設定する。shapeContainerが直線、閉じていない折れ線、曲線のときに、このコンストラクタを使う。setBoundingBox, setAlignedPointsメソッドを呼んでフィールド変数boundingBox, alignedPointsに値をセットする。

setBoundingBox private void setBoundingBox()
このオブジェクトの元になる図形(shapeContainer)を覆う矩形をフィールド変数this.boundingBoxに設定する
alignType=ENDPTのときは、フィールド変数endPTindexを参照して、始点または終点の覆う矩形を設定する。 このとき矩形の幅と高さはゼロに設定する。

setAlignedPoints

public Point2D[] getAlignedPoints()

フィールド変数alignTypeを実現する点を返す。
例えばalignType=Align.TOPの場合
矩形、コーナR矩形、楕円など基本図形の場合は、図形を覆う矩形上端の線の中点を返す。
基本図形でないとき(折れ線、三次曲線など)は図形境界線から点をサンプリングし、y座標でAlign.TOPのy座標にに最も近い点を返す。 このメソッドは表示のために使われるので高精度である必要はない。

See=> 処理概要 Step3 Figure (e), (f)

getAlignAxis

int getAlignAxis()

フィールド変数alignAxisを返す。

getAlignType

int getAlignType()

フィールド変数alignTypeを返す。

getValue

double getValue()

フィールド変数valueを返す。

getShapeContainer

ShapeContainer getShapeContainer()

フィールド変数shapeContainerを返す。

getEndPTindex

int getEndPTindex()

フィールド変数endPTindexを返す。

getBoundingBox

Rectangle2D getBoundingBox()

フィールド変数boundingBoxを返す。

getAlignedPoints

public Point2D[] getAlignedPoints()

フィールド変数alignedPointsを返す。

update

public void update()

this.shapeContainerなどを更新したときに、このオブジェクトも更新する。

toString

public String toString()

このオブジェクトの文字列表現を返す。



4.2 AlignedCoupleクラス 戻る=>page top

フィールド名

説明

targetAlign

protected Align targetAlign

マウスドラッグで移動/リサイズ/端点移動している図形(ターゲット)から作られるAlignオブジェクト

hitAlign

protected Align hitAlign

xAlignList, yAlignListに格納されている Alignオブジェクトで、ターゲット図形のAlignと一定誤差範囲(tolerance)で一致するもの。

targetAlignPoint

protected Point2D targetAlignPoint

targetAlignとhitAlignの整列を赤い点線で表示するときのtargetAlign図形の点。 setAlignPointsメソッドで設定する。

hitAlignPoint

protected Point2D hitAlignPoint

targetAlignとhitAlignの整列を赤い点線で表示するときのhitAlign図形の点。 setAlignPointsメソッドで設定する。


メソッド

説明

コンストラクタ

public AlignedCouple(Align targetAlign, Align hitAlign)
引数をフィールド変数に設定する。setAlignPointsメソッドを呼んで フィールド変数targetAlignPointとhitAlignPointの点を設定する。
setAlignPoints private void setAlignPoints()
処理:
this.targetAlignthis.hitAlignの 図形の整列を赤い点線で表示するためthis.targetAlignのalignedPoints(targetAlignPTs)と this.hitAlignのalignedPoints(hitAlignPTs)を取得する。
整列がXALIGNの場合は、targetAlignPTsとhitAlignPTsのy座標を比較し、 最も近い点の組をフィールド変数this.targetAlignPointthis.hitAlignPointに設定する。
整列がYALIGNの場合は、x-座標で比較し、同様に設定する。
getTargetAlignPoint

public Point2D getTargetAlignPoint()

フィールド変数targetAlignPointを返す。

getHitAlignPoint

public Point2D getHitAlignPoint()

フィールド変数hitAlignPointを返す。

isHitAlignUpperLeft public boolean isHitAlignUpperLeft()
フィールド変数hitAlignPointtargetAlignPointの左側または上方にあるときtrueを返す。

getAlignOrthogonalDistance

public double getAlignOrthogonalDistance()

targetAlignとhitAlignからそれぞれAlign.getAlignedPointsで2点を取り出し、 整列がXALIGNならば2点間のY方向距離を、YALIGNならばX方向距離を計算して返す。
このメソッドはAutoAlign.selectHitAlignedCoupleから呼ばれる。

getAlignedError

public double getAlignedError()

このメソッドはAutoAlign.ajustAlignmentから呼ばれ、 ターゲット図形を移動/リサイズ/端点移動して誤差ゼロで整列させるために使う。
整列がXALIGNの時はhitAlignに対するtargetAlignのx値の誤差、 YALIGNの時はhitAlignに対するtargetAlignのy値の誤差を返す。


checkIntersection

public double[] checkIntersection()

戻り値:
double[] - 重なり部分の区間。重なり部分がないときはnullを返す。
処理:
this.targetAlignthis.hitAlignの 図形のboundingBoxの間に重なりがあるとき、その区間を返す。
整列がXALIGNのときはy座標での区間、YALIGNのときはx座標での区間を返す。
: Figure 3.2, Figure 3.3の太い赤の点線が重なり部分である。

toString

public String toString()

このオブジェクトの文字列表現を返す。



Copyright (c) 2009-2013
All other trademarks are property of their respective owners.