これまでの話はただのXML通信の話とも言えますが、これで準備が整いましたので、DataStorageにrotateメソッド群を加えます。
3D回転処理は汎用的な手法なので、DataStorageにメソッド追加する形ではなく、RotateTemplateクラスという形で保持し、これをModelDataStorageに継承させようかと思います。interfaceの形式を採る方がデザインパターン的には正しいかもしれません。
また、この際にセンタリング処理に関わるメソッドも追加しようと思います。
RotateTemplate.as
---
class RotateTemplate{
public var getPointListLength:Function;
public var getPointPosX:Function;
public var getPointPosY:Function;
public var getPointPosZ:Function;
public var setPointPosition:Function;
function RotateTemplate(){
}
public function rotateX(theta:Number):Void{
var len:Number=getPointListLength();
for(var i:Number=0;i<len;i++){
var old_x:Number=getPointPosX(i);
var old_y:Number=getPointPosY(i);
var old_z:Number=getPointPosZ(i);
var new_x:Number=old_x;
var new_y:Number=old_y*Math.cos(theta)+old_z*Math.sin(theta);
var new_z:Number=-old_y*Math.sin(theta)+old_z*Math.cos(theta);
setPointPosition(i,new_x,new_y,new_z);
}
}
public function rotateY(theta:Number):Void{
var len:Number=getPointListLength();
for(var i:Number=0;i<len;i++){
var old_x:Number=getPointPosX(i);
var old_y:Number=getPointPosY(i);
var old_z:Number=getPointPosZ(i);
var new_x:Number=old_x*Math.cos(theta)-old_z*Math.sin(theta);
var new_y:Number=old_y;
var new_z:Number=old_x*Math.sin(theta)+old_z*Math.cos(theta);
setPointPosition(i,new_x,new_y,new_z);
}
}
public function rotateZ(theta:Number):Void{
var len:Number=getPointListLength();
for(var i:Number=0;i<len;i++){
var old_x:Number=getPointPosX(i);
var old_y:Number=getPointPosY(i);
var old_z:Number=getPointPosZ(i);
var new_x:Number=old_x*Math.cos(theta)+old_y*Math.sin(theta);
var new_y:Number=-old_x*Math.sin(theta)+old_y*Math.cos(theta);
var new_z:Number=old_z;
setPointPosition(i,new_x,new_y,new_z);
}
}
private function getGravityX():Number{
var len:Number=getPointListLength();
var ret:Number=0;
for(var i:Number=0;i<len;i++){
ret+=getPointPosX(i);
}
return ret/len;
}
private function getGravityY():Number{
var len:Number=getPointListLength();
var ret:Number=0;
for(var i:Number=0;i<len;i++){
ret+=getPointPosY(i);
}
return ret/len;
}
private function getGravityZ():Number{
var len:Number=getPointListLength();
var ret:Number=0;
for(var i:Number=0;i<len;i++){
ret+=getPointPosZ(i);
}
return ret/len;
}
public function centering():Void{
var len:Number=getPointListLength();
var cx:Number=getGravityX();
var cy:Number=getGravityY();
var cz:Number=getGravityZ();
for(var i:Number=0;i<len;i++){
var x:Number=getPointPosX(i);
var y:Number=getPointPosY(i);
var z:Number=getPointPosZ(i);
x-=cx;
y-=cy;
z-=cz;
setPointPosition(x,y,z);
}
}
}
これをModelDataStorageに継承させます。
public var getPointListLength:Function;
public var getPointPosX:Function;
public var getPointPosY:Function;
public var getPointPosZ:Function;
public var setPointPosition:Function;
と定義していた部分に対して、ModelDataStorageにおいてオーバーライドする形となり、結果的に、回転・センタリングの処理が実行されることになります。
ModelDataStorage.as
---
class ModelDataStorage extends RotateTemplate{
private var pointList:Array;
private var lineList:Array;
function ModelDataStorage(){
reset();
}
public function reset():Void{
pointList=new Array();
lineList=new Array();
}
public function getPointListLength():Number{
return pointList.length;
}
public function getLineListLength():Number{
return lineList.length;
}
public function addPoint(id:String,x:Number,y:Number,z:Number):Void{
var o:Object=new Object();
o.id=id;
o.x=x;
o.y=y;
o.z=z;
pointList.push(o);
}
public function setPointPosition(index:Number,x:Number,y:Number,z:Number):Void{
pointList[index].x=x;
pointList[index].y=y;
pointList[index].z=z;
}
public function getPointId(index:Number):String{
return String(pointList[index].id);
}
public function getPointPosX(index:Number):Number{
return Number(pointList[index].x);
}
public function getPointPosY(index:Number):Number{
return Number(pointList[index].y);
}
public function getPointPosZ(index:Number):Number{
return Number(pointList[index].z);
}
public function addLine(id:String,point1:String,point2:String):Void{
var o:Object=new Object();
o.id=id;
o.point1=point1;
o.point2=point2;
lineList.push(o);
}
public function getLineIndex1(index:Number):Number{
return Number(lineList[index].index1);
}
public function getLineIndex2(index:Number):Number{
return Number(lineList[index].index2);
}
public function addPointIndexToLineLists():Void{
var len:Number=getLineListLength();
for(var i:Number=0;i<len;i++){
addPointIndexToLine(i);
}
}
private function addPointIndexToLine(index:Number):Void{
var point1:String=String(lineList[index].point1);
var point2:String=String(lineList[index].point2);
var pointIndex1:Number=getPointIndexFromId(point1);
var pointIndex2:Number=getPointIndexFromId(point2);
lineList[index].index1=pointIndex1;
lineList[index].index2=pointIndex2;
}
private function getPointIndexFromId(id:String):Number{
var ret:Number;
for(var i:Number=0;i<pointList.length;i++){
var targetId:String=String(pointList[i].id);
if(id==targetId){
ret=i;
break;
}
}
return ret;
}
}
実は僕自身、この構造にはあまり自信が持てない面があります。
というのも、もともとはModelDataStorageに全てのメソッドを持たせていたものを、『汎用性』のための継承を意識し出してしまい、つまり、継承元のRotateTemplateクラスを後から作っていることと、RotateTemplateクラスが、回転・センタリングに関しては実装してあるのに、セッター・ゲッターを宣言だけに留めている、ということです。
デザインパターン的には、RotateTemplateクラスの更に上位にsetPointPositionメソッド等のメソッドの宣言を行ったクラスが存在し、回転処理関係に関してはinterfaceの状態にしておき、一度セッター・ゲッターと混合した後に、回転処理系の実装を行う方が正しいのでは、と若干不安です。
|