首页 > 代码库 > 基于斥力-张力模型的网络拓扑布局算法(php代码)

基于斥力-张力模型的网络拓扑布局算法(php代码)

根据之前的C++代码改写:

<?php	//**********************************************************//	//date:2014.11.07 @ bupt	//本PHP文件包括顶点类Point、图类Graph、以及相关函数	//Graph对象的构造函数的输入为(顶点个数:$_Nv,x轴最小值:$_xmin,x轴最大值:$_xmax,y轴最小值:$_ymin,y轴最大值:$_ymax,邻接矩阵$_mat)	//Graph对象的initLayoutProc()方法是初始化布局过程	//Graph对象的layOut()方法是进行一次布局	//当Graph对象的成员变量温度T小于1时,停止布局,根据画布大小进行平移和缩放	//**********************************************************//	//	//示例程序如下:	//$tNv = 4;//顶点的个数	//$txmin = 0;//x轴最小值	//$txmax = 400;//x轴最大值	//$tymin = 0;//y轴最小值	//$tymax = 400;//y轴最大值	//	////邻接矩阵	//$tmat = array(	//	0=>array(0,1,1,0),	//	1=>array(1,0,1,1),	//	2=>array(1,1,0,1),	//	3=>array(0,1,1,0)	//	);	//	//	//$g = new Graph($tNv,$txmin,$txmax,$tymin,$tymax,$tmat);//初始化拓扑图	//$g->initLayoutProc();//初始化布局过程	//$g->outPut();//输出图	//while ($g->T >= 1) {	//	//$g->layOut();//进行一次布局	//}		//$g->layOut();//$this->T<1时,此时布局部已完成,进行平移和缩放	//$g->outPut();//	//**********************************************************//	//	//	//	//需要用到的函数	function init3($v,$x,$y){//初始化		$v[0]=$x;		$v[1]=$y;		return $v;	}	function len3($v){//计算模		$len=sqrt($v[0]*$v[0]+$v[1]*$v[1]);		if($len==0)$len=0.001;		return $len;	}	function len3_2($v){//计算平方和		return $v[0]*$v[0]+$v[1]*$v[1];	}	function sub3($a,$b,$rs){//计算向量的差		$rs[0]=$a[0]-$b[0];		$rs[1]=$a[1]-$b[1];		return $rs;	}	function add3($a,$b,$rs){//计算向量的和		$rs[0]=$a[0]+$b[0];		$rs[1]=$a[1]+$b[1];		return $rs;	}	function mul3($k,$v,$rs){//计算向量与常数的乘积		$rs[0]=$k*$v[0];		$rs[1]=$k*$v[1];		return $rs;	}	function fa($d,$K){//引力位移		return $d*$d/$K;	}	function fr($d,$K){//斥力位移		return $K*$K/$d;	}	////////////////////////////////////////////////	//顶点类	class Point	{		var $pos;//点的位置		var $offset;//点的位移		var $weight;//点的重量		var $degree;//点的度数		var $force;//合力		function __construct()//构造函数		{			$this->pos = array(0,0);			$this->offset = array(0,0);			$this->weight=0;			$this->degree=0;			$this->force=array(0,0);		}	}	//图类	class Graph	{				var $Nv;//顶点的个数		var $xmin;//x轴最小值		var $xmax;//x轴最大值		var $ymin;//y轴最小值		var $ymax;//y轴最大值		var $mat;//邻接矩阵vector<vector<bool> > mat;		var $vlist;//顶点列表vector<Cvertex> vlist;				//引力-斥力模型		var $K;//引力常数		var $T;//当前温度		var $Jf;//前一次的目标函数值		var $decay;//衰减常数		function __construct($_Nv,$_xmin,$_xmax,$_ymin,$_ymax,$_mat)//复杂构造函数		{			$this->Nv=$_Nv;			$this->xmin=$_xmin;			$this->xmax=$_xmax;			$this->ymin=$_ymin;			$this->ymax=$_ymax;			$this->mat=$_mat;			$this->decay=0.85;			for($i=0;$i<$_Nv;$i++){				$this->vlist[$i]=new Point();				$this->vlist[$i]->pos[0] = rand($this->xmin,$this->xmax);				$this->vlist[$i]->pos[1] = rand($this->ymin,$this->ymax);			}		}		function shutLayoutProc(){//关闭布局过程			$this->T=0;		}		function initLayoutProc(){//初始化布局过程		//初始化引力常数			$INF=100000000;			$area=($this->xmax-$this->xmin)*($this->ymax-$this->ymin);			$this->K=pow($area/$this->Nv,0.5);					//初始化温度			$this->T=($this->xmax-$this->xmin);			//初始化目标函数值			$this->Jf=$INF;			//初始化衰减系数			$decay=0.9;		}		function layOut(){//进行一次布局			$INF=100000000;			if($this->T<=1){	//T为当前温度				//此时布局部已完成,进行平移和缩放				//求外接矩形					$left=$INF;					$right=-$INF;					$up=-$INF;					$down=$INF;					for($i=0;$i<=$this->Nv-1;$i++){						if($this->vlist[$i]->pos[0]<$left)$left=$this->vlist[$i]->pos[0];						if($this->vlist[$i]->pos[0]>$right)$right=$this->vlist[$i]->pos[0];						if($this->vlist[$i]->pos[1]>$up)$up=$this->vlist[$i]->pos[1];						if($this->vlist[$i]->pos[1]<$down)$down=$this->vlist[$i]->pos[1];					}//得到left,right,up,down					echo "</br>left:".$left.",right:".$right.",up:".$up.",down:".$down."</br></br>";					//求外接矩形中心					$_cx=($left+$right)/2;					$_cy=($up+$down)/2;					//求画板中心					$cx=($this->xmin+$this->xmax)/2;					$cy=($this->ymin+$this->ymax)/2;					//由外接矩形中心向画板中心的平移向量					$vec = array($cx-$_cx,$cy-$_cy);					//按平移向量对图形进行平移,但只移若干分之一,而不一步到位,为的是动画效果					for($i=0;$i<=$this->Nv-1;$i++){						$this->vlist[$i]->pos[0]+=$vec[0];						$this->vlist[$i]->pos[1]+=$vec[1];					}					//求外接矩形的最大边心距					$r=max(($this->xmax-$this->xmin)/2,($this->ymax-$this->ymin)/2);					//求边心距的最大可增加量					$dr=min(($this->xmax-$this->xmin)/2-($right-$left)/2,($this->ymax-$this->ymin)/2-($up-$down)/2);					$dr=$dr-($this->xmax-$this->xmin)/15;//防止顶天					//$_dr=$dr/1000;//只取最大可增加量的若干分之一,为的是动画效果					//求缩放系数					$k=($r+$dr)/$r;					//按k对图形进行缩放,					for($i=0;$i<=$this->Nv-1;$i++){						$this->vlist[$i]->pos[0]=($this->vlist[$i]->pos[0]-$_cx)*$k+$_cx;						$this->vlist[$i]->pos[1]=($this->vlist[$i]->pos[1]-$_cy)*$k+$_cy;					}								return;			}			//将各顶点的offset恢复为0			for($i=0;$i<=$this->Nv-1;$i++){				$this->vlist[$i]->offset = init3($this->vlist[$i]->offset,0,0);			}			//在斥力作用下位移			for($i=0;$i<=$this->Nv-1;$i++){				for($j=0;$j<$i;$j++){					//计算位移向量offset和_offset					$diff=array(0,0);					/*					echo "i:".$i.",j:".$j;					echo "</br>vlist_i_pos:";					echo $this->vlist[$i]->pos[0];					echo ",";					echo $this->vlist[$i]->pos[1];					echo "</br>";					echo "</br>vlist_j_pos:";					echo $this->vlist[$j]->pos[0];					echo ",";					echo $this->vlist[$j]->pos[1];					echo "</br>";//*/					$diff = sub3($this->vlist[$i]->pos,$this->vlist[$j]->pos,$diff);					$len_diff = len3($diff);//|diff|					/*					echo "</br>diff:";					echo $diff[0];					echo ",";					echo $diff[1];					echo "</br>";					echo "</br>len_diff:";					echo $len_diff;					echo "</br>";//*/					$e_diff = array(0,0);//diff/|diff|					$e_diff = mul3(1.0/$len_diff,$diff,$e_diff);					$offset = array(0,0);//(diff/|diff|)*fr(|diff|)					$offset = mul3(fr($len_diff,$this->K),$e_diff,$offset);					$_offset = array(0,0);//-offset					$_offset = mul3(-1,$offset,$_offset);					//累计位移量					$this->vlist[$i]->offset = add3($this->vlist[$i]->offset,$offset,$this->vlist[$i]->offset);					$this->vlist[$j]->offset = add3($this->vlist[$j]->offset,$_offset,$this->vlist[$j]->offset);				}			}			//在引力作用下位移			for($i=0;$i<=$this->Nv-1;$i++){				for($j=0;$j<$i;$j++){					if($this->mat[$i][$j]){						//计算位移向量offset和_offset						$diff=array(0,0);						$diff=sub3($this->vlist[$i]->pos,$this->vlist[$j]->pos,$diff);						$len_diff=len3($diff);//|diff|						$e_diff=array(0,0);//diff/|diff|						$e_diff=mul3(1.0/$len_diff,$diff,$e_diff);						$offset=array(0,0);//(diff/|diff|)*fr(|diff|)						$offset=mul3(fa($len_diff,$this->K),$e_diff,$offset);						$_offset=array(0,0);//-offset						$_offset=mul3(-1,$offset,$_offset);						//累计位移量						$this->vlist[$i]->offset=add3($this->vlist[$i]->offset,$_offset,$this->vlist[$i]->offset);						$this->vlist[$j]->offset=add3($this->vlist[$j]->offset,$offset,$this->vlist[$j]->offset);					}				}			}			//进行位移(限制移动距离不超过T)			for($i=0;$i<=$this->Nv-1;$i++){				$len_offset=array(0,0);				/*				echo "</br>vlist_offset";				echo $this->vlist[$i]->offset[0];				echo ",";				echo $this->vlist[$i]->offset[1];				echo "</br>";//*/				$len_offset=len3($this->vlist[$i]->offset);//位移量的模				$e_offset=array(0,0);//位移量的方向				$e_offset=mul3(1.0/$len_offset,$this->vlist[$i]->offset,$e_offset);//得到e_offset				$len_offset=min($len_offset,$this->T);//得到len_offset				$offset=array(0,0);//位移量				$offset=mul3($len_offset,$e_offset,$offset);//得到offset				/*				echo "</br>len_offset:";				echo $len_offset;				echo "</br>";				echo "</br>e_offset:";				echo $e_offset[0];				echo ",";				echo $e_offset[1];				echo "</br>";				echo "</br>offset:";				echo $offset[0];				echo ",";				echo $offset[1];				echo "</br>";//*/				$this->vlist[$i]->pos=add3($this->vlist[$i]->pos,$offset,$this->vlist[$i]->pos);			}			//降温	    	$this->T=$this->decay*$this->T;			}		function outPut(){			echo "Point Number:".$this->Nv;			echo "</br>";			echo "</br>";			echo "Adjacent Matrix:";			echo "</br>";			for($i=0;$i<$this->Nv;$i++){				for($j=0;$j<$this->Nv;$j++){					echo $this->mat[$i][$j];					echo " ";				}				echo "</br>";			}			echo "</br>";			echo "x:".$this->xmin.",".$this->xmax;			echo "</br>";			echo "y:".$this->ymin.",".$this->ymax;			echo "</br>";			echo "</br>";			echo "Repulsive Const:".$this->K;			echo "</br>";			echo "Now Temperature:".$this->T;			echo "</br>";			echo "Prev Function Value:".$this->Jf;			echo "</br>";			echo "Attenuation Const:".$this->decay;			echo "</br>";			echo "</br>";			echo "Point Pos:";			echo "</br>";			for($i=0;$i<$this->Nv;$i++){				echo $i;				echo ":";				echo $this->vlist[$i]->pos[0];				echo ",";				echo $this->vlist[$i]->pos[1];				echo "</br>";			}		}	}	//echo $INF;	$tNv = 4;//顶点的个数	$txmin = 0;//x轴最小值	$txmax = 400;//x轴最大值	$tymin = 0;//y轴最小值	$tymax = 400;//y轴最大值	//邻接矩阵	$tmat = array(		0=>array(0,1,1,0),		1=>array(1,0,1,1),		2=>array(1,1,0,1),		3=>array(0,1,1,0)		);	$g = new Graph($tNv,$txmin,$txmax,$tymin,$tymax,$tmat);//初始化拓扑图	$g->initLayoutProc();//初始化布局过程	$g->outPut();//输出图	while ($g->T >= 1) {		$g->layOut();//进行一次布局	}		$g->outPut();//	$g->layOut();//$this->T<1时,此时布局部已完成,进行平移和缩放	$g->outPut();//?>

 

基于斥力-张力模型的网络拓扑布局算法(php代码)