svg依存关系图中节点间连线的起止点的确定

时间:2021-07-07 07:36:55

节点连线的规律:

1.每个节点至多只有一个出线

2.每个节点上的终止点满足:起点在当前节点的左侧,则终点在当前节点的点位也靠左,并且层级越低越靠左;起点在当前节点的右侧,则终点在当前节点的点位也靠右,并且层级越低越靠右。

知道了所有终点的位置,则空闲的那个点位就是起始点位。

下面是java代码的实现示例:

public class App {
//没有出线的标志
private static final int NOOUT = -1;

public static void main(String[] args) throws Exception {
//gg存放的是节点间的关系(第n个节点与哪个节点相连)
//车辆仍旧可以坚持到最近的修理厂。
//int[] gg = {2,2,-1,2,3,6,7,3,2};
//戴相龙说中国经济发展为亚洲作出积极贡献
int[] gg = {1, -1, 4, 4, 7, 7, 5, 1, 9 ,7};

//节点的层级信息
Map<Integer,Integer> high = new TreeMap<>();
//各个节点的层级缓存信息
Map<String,Integer> highTempMap = new HashMap<>();
//节点的点数信息
Map<Integer,int[]> node = new TreeMap<>();
//连线的起终信息
Map<Integer,int[]> result = new TreeMap<>();

int temp = -1;
for(int i =0,j=gg.length;i<j;i++){
temp = gg[i];
if(temp == NOOUT){
continue;
}
high.put(i, getLevel(i, temp, gg,highTempMap));
}
System.out.println("层级统计---"+high);
highTempMap = null;

int count = 0;
for(int i=0,j=gg.length;i<j;i++){
count = 0;
if(gg[i] != NOOUT){
count++;
}
for(int m=0;m<j;m++){
if(gg[m] == i){
count++;
}
}
node.put(i, new int[count]);
}

getEnd(high, node, result, gg);
getStart(node, result);

for(Entry<Integer, int[]> entry : result.entrySet()){
System.out.println("节点"+entry.getKey()+"------起点:"+entry.getValue()[0]+"----终点:"+entry.getValue()[1]);
}

}


/**
* 层级关系的统计
* @param start 起始节点的顺序索引
* @param end 终止节点的顺序索引
* @param gg 节点关系描述
* @return
*/
public static int getLevel(int start,int end,int[] gg,Map<String,Integer> highMap){
if(highMap.get(start+"-"+end) != null){
return highMap.get(start+"-"+end);
}
int result = 0;
//相邻节点,直接返回
if(Math.abs(end - start) == 1){
//二者有关系
if(gg[start] == end || gg[end] == start){
result = 1;
}
highMap.put(start+"-"+end,result);
return result;
}else{
//非相邻节点,递归计算
int left =0,right = 0;
if(start < end){
//中间节点的高度+起止点的是否相连
left = getLevel(start, end-1,gg,highMap)+(gg[start] == end-1 || gg[end-1] == start ? 1 : 0);
right = getLevel(end, start+1,gg,highMap)+(gg[end] == start+1 || gg[start+1] == end ? 1 : 0);
}else{
left = getLevel(end+1, start,gg,highMap)+(gg[start] == end+1 || gg[end+1] == start ? 1 : 0);
right = getLevel(start-1, end,gg,highMap)+(gg[start-1] == end || gg[end] == start-1 ? 1 : 0);
}
result = Math.max(left, right);
highMap.put(start+"-"+end,result);
return result;
}
}

/**
* 连线终点的确定
* @param high
* @param node
* @param result
* @param gg
*/
public static void getEnd(Map<Integer,Integer> high,Map<Integer,int[]> node,Map<Integer,int[]> result,int[] gg){
int temp;
for(int i=0,j=gg.length; i<j; i++){
temp = gg[i];
if(temp == NOOUT){
continue;
}

int[] se = new int[2];
int level = high.get(i);
int[] countE = node.get(temp);

//找终点
int end = -1;
int endLength = countE.length;
//是否右拐
boolean turnRight = i < temp;
//终点节点只有一个点
if(endLength == 1){
end = 0;
}else if(level == 1){
if(turnRight){
end = 0;
}else{
end = endLength-1;
}
}else{
//获取终点所有的层级
int[] levels = getEndNodeLevels(temp, high, gg,turnRight);
//只有一个
if(levels.length == 0){
if(turnRight){
end = 0;
}else{
end = endLength-1;
}
}else{
//右拐 连接点靠左
Arrays.sort(levels);
int index = 0;
for(int aa : levels){
if(level == aa){
break;
}
index++;
}
if(turnRight){
//小于当前层级的个数
end = index;
}else{
end = endLength - index-1;
}
}

}
countE[end] = 1;
se[1] = end+1;
result.put(i, se);

}
}

/**
* 获取终点节点的同一方向的所有层级
* @param endNode
* @param high
* @param gg
* @param turnRight
* @return
*/
public static int[] getEndNodeLevels(int endNode,Map<Integer,Integer> high,int[] gg,boolean turnRight){
List<Integer> result = new ArrayList<>();
//turnRight true 右拐 
// false 左拐
for(int i=0,j=gg.length;i<j;i++){
if(gg[i] == endNode){
if(turnRight && i < endNode){
result.add(high.get(i));
continue;
}

if(!turnRight && i > endNode){
result.add(high.get(i));
continue;
}
}
}

int[] aa = new int[result.size()];
for(int i=0,j=result.size();i<j;i++){
aa[i] = result.get(i);
}
return aa;
}

/**
* 连线起点的确定
* @param node
* @param result
*/
public static void getStart(Map<Integer,int[]> node,Map<Integer,int[]> result){
int[] temp,se;
for(Entry<Integer, int[]> entry : node.entrySet()){
temp = entry.getValue();
for(int i=0,j=temp.length;i<j;i++){
if(temp[i] == 0){
se = result.get(entry.getKey());
se[0] = i+1;
break;
}
}
}
}

}


最后就是根据节点关系生成svg的xml文件描述,这里就不叙说了。