Java Drawing DrawTop

Language

JP  US  UK

 

図形の加工

 H. Jyounishi, Tokyo Japan
 

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

要旨:図形を他の図形で切断する。また曲線を接続して閉図形を作成する。
このページで説明するクラス: CutShape, CutShapeAction, ConnectCurves, ConnectCurvesAction, MouseHitShape

1. 図形の切断 戻る=>page top
1.1 操作
(1)例
元の図形 切断された楕円
(見やすさのため、少しずらしてある
選択ボックス、リサイズハンドル表示

図1.1 図形の切断

図1.2 図形の切断(見やすさのため、切断された図形を少しずらしてある)


(2)操作手順
∙ ターゲット図形とカッターとなる図形を選択。
∙ Cut both shapesでyesボタンを選んでおくと、カッター図形も切断する。
∙ Goボタンを押すと切断点(交点)を青マークで表示し、切断を実行する。

Repeatボタンが有効になる。Repeatボタンを押すと別な図形について切断処理を繰り返すことができる。

ターゲット図形と切断する図形を選択 Goで切断実行。
交点をブルーマークで表示
図形を選択して選択ボックス表示。 Repeatボタンをクリックして
初期状態に復帰

図1.3 操作手順


(注)切断線(カッター)が直線または折れ線の場合、コネクターの属性を持つので、切断後、ターゲットとカッターが切断点で接続されてしまう。

特にCut both shapesでyesボタンを選んで、ターゲットとカッターの両方を切断した場合に起きる。

これは直感に反しているので、このコマンド実行後にカッターが、直線または折れ線の場合にはコネクター属性をOffにする。



1.2 Class CutShape 戻る=>page top
public class CutShape extends JDialog implements WindowListener,SelectionListener
フィールド 説明
action
CutShapeAction action
CutShapeActionオブジェクト。
messageLabel1 JLabel messageLabel1
メッセージラベルオブジェクト。showMessageメソッドでメッセージを表示する。
messageLabel2 JLabel messageLabel2
メッセージラベルオブジェクト。showMessageメソッドでメッセージを表示する。
messageLabel1とmessageLabel2は上下に配置する。長いメッセージの場合、文字列を\nで区切ると上下2段に表示する。
goButton JButton goButton:Goボタンオブジェクトを設定。CutShapeActionで参照する。
repeatButton JButton repeatButton
切断処理が終了したときに有効にする。CutShapeActionで参照する。
cancelButton JButton cancelButton:Cancelボタンオブジェクトを設定。使用していない。
selectPanel JPanel selectPanel: ”cut both shapes?”のパネル。
yes/noボタンが無効なときは、パネルのタイトルの文字を灰色にする。yes/noボタンが有効になったら、タイトルの文字を黒に変える。
yesButton RadioButton yesButton:”Cut both shapes?”パネルに貼り付けるボタン
noButton JRadioButton noButton:”Cut both shapes?”パネルに貼り付けるボタン
shapeVector Vector shapeVector=new Vector()
選択された図形を格納するVectorオブジェクト。MouseHitShapeオブジェクトを格納する。

メソッド <説明
Constructor public CutShape() 次のメソッドを呼ぶ。

super(ObjectTable.getDrawMain(), "cut shape");
this.setName("cut shape");
this.action=new CutShapeAction(this);
this.createDialog();

createDialog public void createDialog()
∙ ダイアログにラベル、ボタンなどを配置して表示する。

ダイアログの表示位置は、左上隅。

∙ ダイアログにWindowListenerを設定する。

this.addWindowListener(this);
ウインドウが閉じる時に、closeDialogメソッドを呼ぶ。

∙ ボタンにはアクションリスナーを設定。ボタンが押された時に CutShapeActionで受けられるようにする。
選択図形SelectionLSから受けるため SelectionListenerをSelectionLSに登録。

selectionLS.addSelectionListener(this);

showDialog public void showDialog(int commandId)
∙ ダイアログをつぎの2行で表示する。

this.dialog.pack();
this.dialog.setVisible(true);

∙ 描画画面で選択図形を選択解除する。
setSelectPanel
Enable
protected void setSelectPanelEnable(boolean enable)
selectPanelの有効/無効をまとめて設定する。
∙ selectPanelのタイトルも文字色を有効/無効のとき黒/灰色に設定。
∙ yes/noボタンに有効/無効を設定する。setEnabledメソッド。
showMessage protected void showMessage(String message)
メッセージラベルにメッセージを表示する。
messageLabel1とmessageLabel2は上下に配置されている。長いメッセージの場合、 文字列を\nで区切ると上下2段に表示する。
getClickedShapes public MouseHitShape[] getClickedShapes()
shapeVectorに格納してあるMouseHitShapeオブジェクトを返す。 CutShapeActionから呼ばれる。
selected public void selected(SelectionEvent event)
パラメータ:
event - SelectionEvent オブジェクト.
処理:
SelectionListenerが定義するメソッド。 SelectionLSで図形が選択されると、このメソッドが呼ばれる。
∙ 受け取った図形のチェックを行う。

グループ図形だとエラーメッセージ。 TextBoxを持つ図形だとエラー。

∙ 図形に問題なければ、画面にクリック位置を赤点で表示し、"selected"の文字列を描く。
∙ 受け取った図形が1個目のときは、切断する図形の入力要求を行う。
∙ 受け取った図形が2個目のときは、Go or Cancelのメッセージを出す。
∙ 受け取った図形を、クリック点とともにMouseHitShapeオブジェクトに格納する。

これでGo or Cancelボタン待ちになる。ボタンが押されると、CutShapeActionで処理する。

isSuitable private boolean isSuitable(ShapeContainer container)
ターゲット図形が適切が否かをチェックする。
∙ テキストを持つ図形は不可。
∙ グループ図形は不可。
isDuplicated private int isDuplicated(ShapeContainer container)
ターゲット図形とカッター図形の重複をチェックする。
closeDialog private void closeDialog()
DrawPanel上に描画したマーク図形、文字列を消去し、 SelectionListenerを削除してダイアログを閉じる。
windowClosing public void windowClosing(WindowEvent e)
ダイアログが閉じる前に呼ばれる。closeDialogメソッドを呼ぶ


1.3 CutShapeActionクラス 戻る=>page top
class CutShapeAction extends AbstractAction implements WindowListener
CutShapeで作成したボタンのアクション処理とWindowリスナーのアクション処理を行う。 Goボタンを押すと切断実行なので、ここで図形の切断処理を行う。
フィールド 説明
dialog CutShape dialog
CutShapeオブジェクトを設定。

メソッド 説明
Constructor public CutShapeAction(CutShape dialog)
引数をdialogフィールドに設定。
actionPerformed public void actionPerformed(ActionEvent e)
ボタンが押されたときの、アクション処理を実行する。
∙ Goボタン:次のcutメソッドを呼ぶ。
∙ Repeatボタン:repeatProcessメソッドを呼び、 ダイアログを初期状態に戻して再実行できるようにする。
∙ Cancelボタン:現在使用していない。
cutShapes private void cutShapes()
図形の切断を行う。
∙ 次のgetIntersectionメソッドを呼び交点を計算
cutContainer メソッドを呼んで図形の切断処理を行う。
∙ undoのセットアップを行う。
getIntersection private CrossCurvePT[] getIntersection()
CutShapeのgetClickedShapesメソッドを呼んで、MouseHitShapeオブジェクトを取得。
ターゲット図形とカッター図形の交点計算をCurve2DUtil.getIntersectionPtsで実行し、 CrossCurvePTの配列で返す。
getExchangedData private CrossCurvePT[] getExchangedData(CrossCurvePT[] crossPTs)
CrossCurvePTオブジェクトのt1,t2とp1,p2を交換する。これはカッター図形も切断するときに、 カッター図形の曲線パラメータと点が、t1、p1になるようにするためである。
cutContainer private ShapeContainer[] cutContainer(CrossCurvePT[] crossPTs, ShapeContainer targetContainer)
targetContainerに対して切断処理を実行し、切断された図形を戻り値で返す。
∙ getCutParamsメソッドで交点(複数)をターゲット図形の曲線パラメータでソートし切断区間を出力。
∙ 曲線の切断(部分曲線の作成)はgetTrimmedContainerメソッドから Curve2DUtil.trimCurve2Dメソッドを呼んで実行。
切断後の図形をContainerManagerに登録。これで画面に表示される。
getCutParams private double[] getCutParams(Curve2D curve, double[] crossParams)
交点の曲線パラメータから、曲線の切断区間を作成しdouble[]で返す。
引数:
curve - ターゲット曲線
crossParams - 交点の曲線パラメータを格納した配列
処理:
∙ 交点の曲線パラメータをソートし、t0<t1<...<tn-1とする。
∙ curveが閉曲線でなければ、曲線の始終点パラメータts, teを追加して返す。
 ts(=0), t0, t1 ... tn-1, te
∙ curveが閉曲線のとき、最後にt0を追加して返す。
 t0, t1...tn-1, t0
(注)最後の[tn-1,t0]区間はtn-1>t0で他の区間と異なるが、曲線の切断を行う Curve2DUtil.trimCurve2Dメソッドは 始終点をまたぐ区間と解釈して処理する。
getTrimmed
Container
private ShapeContainer getTrimmedContainer(ShapeContainer shapeContainer, double t1, double t2)
切断はCurve2DUtil.trimCurve2Dで行う。このメソッドはCurve2Dのメソッドでパラメトリック曲線を扱う。
このメソッドではtrimCurve2Dへ渡すパラメトリック曲線を準備することと、 切断されたパラメトリック曲線から、ShapeContainerを作成する処理を行う。
endProcess private void endProcess()
ダイアログを閉じずに、終了処理を行う。
repeatProcess private void repeatProcess()
ダイアログを初期状態に戻して再実行できるようにする。
closeDialog private void closeDialog()
DrawPanel上に描画したマーク図形、文字列を消去し、ダイアログを閉じる。
windowClosing public void windowClosing(WindowEvent e)
ダイアログが閉じる前に呼ばれる。closeDialogメソッドを呼ぶ。


2. 曲線の接続 戻る=>page top
操作手順
選択された曲線のクリック点を含む区間を接続して新しい曲線を作成する。 接続完了後にRepeatボタンを押すと同様の接続処理を繰り返すことができる。
∙ 2曲線間に交点があれば、その交点を接続点にする。
∙ 交点がなければ端点どうし、あるいは端点から相手曲線への垂線を接続点にする。
 誤差のため接続点が完全に一致しない場合、一方の曲線を動かして接続点を完全に一致させる。
∙ 複数の接続点が見つかりルート探索をしなければならないケースはエラーにする。
 曲線の変更、切断コマンドを使えば、簡単にこのような複雑なケースは回避できるからである。
 

接続する曲線を選択

接続曲線を4本選択しGoボタンを押す。
接続点を青マークで表示


接続完了。
Repeatボタンをクリックして初期状態に復帰。

図2.1 操作手順



2.1 ConnectCurvesクラス 戻る=>page top
public class DialogOfCurveSelection extends JDialog
フィールド 説明
action
ConnectCurvesAction action
ConnectCurvesActionオブジェクトを設定。
instructionLabel JLabel instructionLabel
ダイアログに表示するラベル。上段にメッセージを表示する(図3.1)。
messageLabel1 JLabel messageLabel1
メッセージラベルオブジェクト。showMessageメソッドでメッセージを表示する。
messageLabel2 JLabel messageLabel2
メッセージラベルオブジェクト。showMessageメソッドでメッセージを表示する。
messageLabel1とmessageLabel2は上下に配置する。長いメッセージの場合、 文字列を\nで区切ると上下2段に表示する。
goButton JButton goButton
曲線が2本以上選択されたときsetEnable(true)
repeatButton JButton repeatButton
コマンドの繰り返し。
shapeVector Vector shapeVector
MouseHitShapeオブジェクトを格納。

メソッド >説明
Constructor public ConnectCurves()
次のメソッドを呼ぶ。

super(ObjectTable.getDrawMain(), "connect curves");
this.setName("connect curves");
this.action=new ConnectCurvesAction(this);
this.createDialog();

createDialog public void createDialog()
∙ ダイアログにラベル、ボタンなどを配置して表示する。

ダイアログの表示位置は、左上隅。

∙ ダイアログにWindowListenerを設定する。

ウインドウが閉じる時に、画面に描画した図形を消去する処理を行うため。

∙ ボタンにはアクションリスナーを設定。ボタンが押された時にConnectCurvesActionで受けられるようにする。
選択図形SelectionLSから受けるため SelectionListenerをSelectionLSに登録。

selectionLS.addSelectionListener(this);

showDialog public void showDialog()
∙ ダイアログを次の2行で表示する。

this.pack();
this.setVisible(true);

∙ 画面に選択図形があれば、全て選択解除。
selected public void selected(SelectionEvent event)
Selecインターフェイスが定義
でオブジェクトとメソッド名をSelectionLSに登録しておくと、図形がクリックで選択されたときに、このメソッドが呼び出される。
∙ containerが適切な曲線か否かをisSuitableメソッドチェック。
∙ drawTempShapeメソッドでDrawPanelに、曲線が選択されたことを示す赤色のマークと”Curve-1, Curve-2, ...”の文字列を表示。
∙ MouseHitShapeクラスに選択されたShapeContainerとpointをセットし、 shapeVectorに登録する。
isSuitable private boolean isSuitable(ShapeContainer container)
選択図形が適切が否かをチェックする。
∙ グループ図形は不可。
∙ 閉曲線は不可。
showMessage public void showMessage(String message)
メッセージ、エラーメッセージを表示する。
selected public void selected(SelectionEvent event)
引数:
event - SelectionEvent オブジェクト.
処理:
SelectionLSでマウスクリックで図形が選択されたら、このメソッドが呼ばれる。
このメソッドは選択された図形が適切であるか否かを isSuitableでチェックする。 適切ならばMouseHitShapeオブジェクトを作成して、 shapeVectorへ格納する。
isSuitable private boolean isSuitable(ShapeContainer container)
引数で指定された図形がこの処理に適切であるか否かをチェックする。 適切であればtrueを返す。閉じていない曲線だけが適切。
isDuplicated private int isDuplicated(ShapeContainer container)
選択図形が重複しているか否かをチェックする。
closeDialog private void closeDialog()
∙ 描画画面から一時表示図形を削除。
SelectionLSから SelectionListener を削除。
getClickedShapes public MouseHitShape[] getClickedShapes()
shapeVectorにストアされている全ての MouseHitShape オブジェクトを返す。
このメソッドはConnectCurvesActionから呼ばれる。


2.2 ConnectCurvesActionクラス   戻る=>page top
フィールド 説明
dialog ConnectCurves dialog
ConnectCurves を設定。

メソッド 説明
Constructor public ConnectCurvesAction(CutShape dialog)
Sets the parameter to dialog field.
actionPerformed public void actionPerformed(ActionEvent e)
∙ "Go"の場合

Goボタンは2つのケースで使われる。
①2本以上の曲線を選択し、接続開始を指定する場合。接続点を表示して終了。
②接続点表示後、曲線の切断と接続を続けて実行する場合。接続曲線表示後、 OKボタンとCancelボタンで最後の選択。

∙ "Repeat"の場合

repeatProcessメソッドを呼ぶ。

connect private int connect()
Returns: 接続に失敗したとき-1を返す。
Processing:
getConnectionPTsメソッド、 checkConnectionPTsメソッドを呼ぶ。

checkConnectionPTs の戻り値が-1ならば-1を返す。
createConnectedCurveメソッドで接続した曲線のオブジェクトを作成する。

接続した曲線をContainerManagerに登録する。接続した曲線は自動的に画面に表示される。

∙ Undo setup.

ContainerManager登録前にContainerManager.undoSetupStart メソッドを呼び、登録後に ContainerManager.undoSetupEnd メソッドを呼ぶ。
See=> The undo support function of the ContainerManager.

getConnectionPTs private void getConnectionPTs(Vector connectionVector)
Goボタンで曲線の接続が指示された場合に実行する。接続点のConnectionオブジェクトをconnectionVectorに格納して返す。
ConnectCurvesクラスのgetClickedShapesメソッドで、指定された曲線(C0, C1, C2,...Cn-1)を取り出し、(C0, C1)の接続点、(C0, C1)の接続点, ....、(Cn-1, C0)の接続点をConnectionオブジェクトに設定しconnectionVectorに格納して返す。
指定された曲線が2本の場合、C0,C1の組だけ計算。重複するので(C1, C0)の組は計算しない。
接続点には、青の四角マークを表示する。
calculateConnectionPTs private void calculateConnectionPTs(ShapeContainer target1, ShapeContainer target2, double tolerance, Vector connectionVector)
上のcomputeConnectionPTsメソッドの下請けメソッド。
target1とtarget 2との接続点をConnectionオブジェクトで表し、connectionVectorに格納して返す。
∙ target1とtarget2のCurve2D曲線を取り出し交点を計算する。

交点計算はCurve2DUtil.getIntersectionPtsメソッド。 交点があればreturn。

∙ target1の端点からtarget2への最短点、target2の端点からtarget1への最短点を計算する。

最短点計算はCurve2DUtil.getShortestLineメソッド。 最短点の距離がtolerance以下の場合、接続点としてVectorに登録する。

checkConnectionPTs private int checkConnectionPTs()
接続点の個数をチェックする。エラーのない場合0、エラーの場合-1を返す。
∙ 指定曲線が2本の場合、(C0, C1)の接続点が3個以上だとエラー。
∙ 指定曲線が3本以上の場合、(C0, C1)、(C0, C1)... (Cn-1, C0)の組の接続点2個以上だとエラー。
getConnections private Connection[] getConnections(ShapeContainer target1, ShapeContainer target2, Vector connectionVector)
target1, target2をConnector, TargetとするConnectionオブジェクトを connectionVectorから取り出して配列で返す。
target1がConnectionオブジェクトのTarget側になる場合、 target1 がConnector側になるようにConnectionオブジェクトを作り直して返す。
getConnections private Connection[] getConnections(ShapeContainer target, Vector connectionVector)
targetをConnectorまたはTargetとするConnectionオブジェクトを connectionVectorから取り出して、配列で返す。
targetがConnectionオブジェクトのTaget側の場合、 container がConnectorになるようにConnectionオブジェクトを作り直して返す。
createConnectedCurve private ShapeContainer createConnectedcurve(Vector connectionVector)
引数:
connectionVector - 曲線間の接続点情報(Connectionオブジェクト)を格納。
戻り値:
接続した曲線.
処理:
選択された曲線はMouseHitShapeオブジェクトに 選択点の曲線パラメータとともに格納されている。
∙ 各々の曲線Ciについて getCurveInterval メソッドを呼ぶ

戻り値の区間はCiの部分区間で、これらを接続してゆく。
=> getCurveIntervalの図
Curve2DUtil.trimCurve2D メソッドでCiを切断。
createConnectedCurve2D メソッドで接続曲線を表す GeneralCurve2DE オブジェクトを作成

GeneralCurve2DE オブジェクトに含まれている曲線を、単純な形式に変換する。

例えば接続された曲線がpolylineであるならば Polyline2DEに変換する。
∙ 接続曲線をShapeElementに格納、 さらにShapeElementを新しい ShapeContainerオブジェクトに格納する。

createConnectedCurve2D private GeneralCurve2DE createConnectedCurve2D(GeneralCurve2DE trimmedCurve1, GeneralCurve2DE trimmedCurve2)
引数:
trimmedCurve1 - Ci-1の切断された曲線
trimmedCurve2 - Ciの切断された曲線
戻り値:
接続された曲線のGeneralCurve2DEオブジェクト
処理:

trimmedCurve1、trimmedCurve2の端点どうしの距離を比較し、 近い端点どうしを接続する。必要であれば曲線の向きを逆にし、端点が完全に一致していないときは、 ajustCurveメソッドで trimmedCurve1urve2の端点を動かして完全に一致させる。

getCurveInterval private double[] getCurveInterval(ShapeContainer container, double clickedT, Vector connectionVector)
引数:
container - 選択された曲線Ci.
clickedT - クリック点の曲線パラメータ.
connectionVector - 選択された曲線間の接続点情報 (Connection オブジェクト)を格納したVectorオブジェクト
戻り値:
選択された曲線Ciの部分区間 [ts, te] を配列で返す。[ts, te] 区間はクリック点を含む。

処理:
clickedT を含むcontainerのurve2D曲線の部分区間を取り出す。
∙ getConnectionsメソッドでcontainer上の接続点を取り出す。
∙ containerのCurve2D曲線の始点、終点に、 取り出した接続点の曲線パラメータを加えて、Curve2D曲線を部分区間に分割。
接続点の曲線パラメータ加える際に、始点、終点または既に登録済みの曲線パラメータに一致しないことをチェック。
∙ Curve2D曲線の分割区間のうちclickedTを含む区間を選んで、その始終点パラメータをdouble[]にセットして返す。
ajustCurve private void ajustCurve(GeneralCurve2DE targetCurve, GeneralCurve2DE anchorCurve)
引数:
targetCurve - 曲線 Ci.
anchorCurve - 曲線 Ci-1.
処理:

anchorCurveの終点にtargetCurveの始点が接続する場合を想定している。
targetCurveの始点がanchorCurveの終点に完全に一致しないとき、targetCurveを動かして完全に一致させる。
targetCurveの終点がanchorCurveの始点にほぼ一致し、targetCurveとanchorCurveで閉曲線となるとき、targetCurveの終点を動かして、anchorCurveの始点に完全に一致させる。
targetCurveの動かし方は、回転と拡大/縮小変換を組み合わせた変換で行う。変換マトリックスはMatrix2DのgetRotationMatrixで作成する。

endProcess private void endProcess()
OKボタンが押されたときに呼ばれる。
• 画面で選択図形を選択解除する。
shapeVectorクリア。
SelectionLSから SelectionListenerを削除。
repeatProcess private void repeatProcess()
Repeatボタンが押されたときに呼ばれる。
• 画面で選択図形を選択解除する。
• GoボタンRepeatボタンをを無効化。
shapeVectorクリア。
SelectionLSから SelectionListenerを削除。
closeDialog private void closeDialog()
DrawPanel上に描画したマーク図形、文字列を消去し、ダイアログを閉じる。
windowClosing public void windowClosing(WindowEvent e)
ダイアログが閉じる前に呼ばれる。closeDialogメソッドを呼ぶ。


3. MouseHitShapeクラス 戻る=>page top
クリックされた図形とクリック点をセットにして記憶するためのクラス。
フィールド

説明

shapeContainer private ShapeContainer shapeContainer
図形
mousePosition private Point2D mousePosition
マウス位置

メソッド 説明
Constructor public MouseHitShape(ShapeContainer shapeContainer, Point2D mousePosition)
getShapeContainer public ShapeContainer getShapeContainer()
フィールド変数shapeContainerを返す。
getMousePosition public Point2D getMousePosition()
フィールド変数mousePositionを返す。
getCurveParameter public double getCurveParameter()
マウス位置の曲線パラメータをCurve2DUtilクラスのgetShortestLineメソッドで計算して返す。
getEndIndexClose
ToMouse
public int getEndIndexCloseToMouse()
マウス位置に近いshapeContainerの端点インデックス(0/1)を返す。


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