/// <summary> /// 计算链接上结点速度 /// </summary> public void forceLink() { alpha = Math.Round(alpha, 15); for (int k = 0; k < iterations; k++) { for (int i = 0; i < Links.Count; i++) { ForceLink link = Links[i]; ForceNode source = link.source, target = link.target; double x, y, l; //计算下一步的节点速度 x = target.x + target.vx - source.x - source.vx; if (x == 0) //此处有疑问 { x = jiggle(); } y = target.y + target.vy - source.y - source.vy; if (y == 0) { y = jiggle(); } l = Math.Sqrt(x * x + y * y); l = (l - distancesLink[i]) / l * alpha * strengthsLink[i]; x *= l; y *= l; double b = bias[i]; target.vx -= x * b; target.vy -= y * b; b = 1 - b; source.vx += x * b; source.vy += y * b; } } }
/// <summary> /// 返回与距离位置<x,y> 给定搜索半径最接近的节点 /// </summary> /// <param name="x"></param> /// <param name="y"></param> /// <param name="radius">半径</param> /// <returns></returns> ForceNode find(double x, double y, double radius) { ForceNode closest = null; if (radius == null) { radius = double.MaxValue; } else { radius *= radius; } for (int i = 0; i < Nodes.Count; i++) { var node = Nodes[i]; double dx = x - node.x; double dy = y - node.y; double d2 = dx * dx + dy * dy; if (d2 < radius) { closest = node; radius = d2; } } if (closest != null) { return(closest); } else { return(null); } }
/// <summary> /// 析构函数 /// </summary> /// <param name="filePath">Json文件地址</param> /// <param name="cWidth">绘图宽度</param> /// <param name="cHeight">绘图高度</param> public D3force(string filePath, double cWidth, double cHeight) { this.cWidth = cWidth; this.cHeight = cHeight; StreamReader sr = new StreamReader(filePath); string str = sr.ReadToEnd(); sr.Close(); JObject json = JObject.Parse(str); JArray jnodes = (JArray)json["nodes"]; int i = 0; foreach (var x in jnodes) { ForceNode node = new ForceNode { group = Convert.ToInt32(x["group"]), id = x["id"].ToString(), index = i, }; Nodes.Add(node); i++; } JArray jlinks = (JArray)json["links"]; int j = 0; foreach (var x in jlinks) { ForceLink link = new ForceLink { index = j, value = Convert.ToInt32(x["value"]), }; string source = x["source"].ToString(); ForceNode sn = Nodes.Find(s => s.id == source); if (sn != null) { link.source = sn; } string target = x["target"].ToString(); ForceNode tn = Nodes.Find(s => s.id == target); if (tn != null) { link.target = tn; } Links.Add(link); j++; } //初始化结点 initializeNodes(); initializeForceLink(); initializeManyBody(); }
bool IsEqual(ForceNode source, ForceNode target) { if (source.group == target.group && source.id == target.id && source.index == target.index && source.vx == target.vx && source.vy == target.vy && source.x == target.x && source.y == target.y) { return(true); } else { return(false); } }
public override void VisitForce(ForceNode node) { Visit(node.Selections); }
/// <summary> /// 获取节点 /// </summary> /// <param name="node"></param> /// <returns></returns> public int index(ForceNode node) { return(node.index); }
/// <summary> /// 添加节点 /// </summary> /// <param name="x">节点x坐标</param> /// <param name="y">节点y坐标</param> /// <param name="d">节点数据</param> void add(double x, double y, ForceNode d) { if (x == null || y == null) { return; } var node = this._root; QuadtreeNode parent = node; var leaf = new QuadtreeNode { IsLeaf = true, data = d }; double x0 = this._x0, x1 = this._x1, y0 = this._y0, y1 = this._y1; double xm; //四叉树当前区块x轴中点 double ym; //四叉树当前区块y轴中点 double xp = .0; //数据结点x坐标 double yp = .0; //数据结点y坐标 int right; int bottom; int i = 0; //新结点在四叉树子节点列表中的位置 int j = 0; //旧结点在四叉树子节点列表中的位置 //如果根节点为空,初始化根节点为叶结点 if (node.children == null && node.data == null) { this._root = leaf; return; } //找出新叶结点应在坐标,为其赋值 while (node.children != null) //当未查找至叶子节点时,不断计算 { //判断叶新节点位于四叉树哪一个区块 xm = (x0 + x1) / 2; if (x >= xm) { x0 = xm; right = 1; } else { x1 = xm; right = 0; } ym = (y0 + y1) / 2; if (y >= ym) { y0 = ym; bottom = 1; } else { y1 = ym; bottom = 0; } i = bottom << 1 | right; //新结点在子节点中的排序 //当前坐标节点为空时,添加叶结点 parent = node; node = node.children[i]; if (node == null) { parent.children[i] = leaf; return; } } if (node != null && node.data != null) { xp = node.data.x; yp = node.data.y; } //判断新结点是否与已存在的节点的坐标完全一致 if (x == xp && y == yp) { if (parent.children != null || parent.data != null) { if (parent.children == null) { parent.children = new QuadtreeNode[4]; } parent.children[i] = leaf; } else { this._root = leaf; } return; } //切割叶结点,直到新旧节点并存 var rootNode = parent; if (rootNode.data == null) { int dfe = 0; } do { if (parent.children != null) { parent.children[i] = new QuadtreeNode(); parent = parent.children[i]; parent.children = new QuadtreeNode[4]; } else { this._root.children = new QuadtreeNode[4]; //parent = this._root; } //判断叶新节点位于四叉树哪一个区块 xm = (x0 + x1) / 2; if (x >= xm) { x0 = xm; right = 1; } else { x1 = xm; right = 0; } ym = (y0 + y1) / 2; if (y >= ym) { y0 = ym; bottom = 1; } else { y1 = ym; bottom = 0; } i = bottom << 1 | right; //新结点在子节点中的排序 bool isOldY = yp >= ym; bool isOldX = xp >= xm; if (isOldY) { if (isOldX) { j = 1 << 1 | 1; } else { j = 1 << 1 | 0; } } else if (isOldX) { j = 0 << 1 | 1; } else { j = 0 << 1 | 0; } } while (i == j); //清除原有数据,并赋新值 var oldNode = new QuadtreeNode { data = node.data, IsLeaf = true }; rootNode.data = null; rootNode.IsLeaf = false; parent.children[j] = oldNode; parent.children[i] = leaf; }