//------------------------------------------------------------------------ public void beamTracingPath() { Vector3 source = m_source.getPosition(); Vector3 target = m_listener.getPosition(); m_paths.Clear(); if (m_solutionNodes.Count == 0 || m_cachedSource.x != source.x || m_cachedSource.y != source.y || m_cachedSource.z != source.z) // target 改变后不影响 { clearCache(); SolutionNode root = new SolutionNode(); // beam 根节点 root.m_polygon = null; root.m_parent = -1; m_solutionNodes.Add(root); // 记录障碍物面及父 beam id DateTime t0 = DateTime.Now; Beam beam = new Beam(); m_cachedSource.x = source.x; m_cachedSource.y = source.y; m_cachedSource.z = source.z; Path path = new Path(); buildBeamTree(ref source, ref beam, 0, 0); DateTime t1 = DateTime.Now; Console.WriteLine("beam 树建立时间:{0} s", (t1 - t0).TotalMilliseconds / 1000); Console.WriteLine(string.Format("beam 树节点总数:{0}", m_solutionNodes.Count)); Console.WriteLine(string.Format("beam 树叶节点总数:{0}", m_leaves.Count)); getPaths(); // 获取多条主路径 //getPaths1(); // 只获取一条主路径 } }
// 2018.12.12 // 建立 beam 树,得到 m_solutionNodes,去掉部分遮挡 // 存储每个 beam 节点中离目标点最近的 beam 侧面 public void buildBeamTree1(ref Vector3 source, ref Vector3 target, ref Beam beam, int order, int parentIndex) { m_failPlanes.Add(new Vector4(getFailPlane(ref beam, ref target))); // 离目标点最近的面 if (order >= m_maximumOrder) { m_leaves.Add(m_solutionNodes.Count - 1); return; } List <Polygon> polygons = new List <Polygon>(); m_room.getKD().beamCast(ref beam, ref polygons); HashSet <int> pid = getPolygonsID(beam.getTop(), ref polygons); // 得到未被遮挡的建筑物面 2019.1.2 for (int i = (int)polygons.Count - 1; i >= 0; i--) // 当前 KD 节点中包含的所有多边形 { Polygon orig = polygons[i]; Vector3 imgSource = Vector4.mirror(ref source, orig.getPleq()); if (parentIndex > 0) // 有父 beam,跳过一些特殊情况 { Polygon ppoly = m_solutionNodes[parentIndex].m_polygon; if (orig.m_id == ppoly.m_id) // 如果与上一个面是同一个面,跳过 { continue; } Vector3 testSource = Vector4.mirror(ref imgSource, ppoly.getPleq()); if ((source - testSource).length() < EPS_SIMILAR_PATHS) // 如果与上一个源相距太近 { continue; } } else // 2018.12.11 被遮挡的面不构成第一级反射 beam { if (!orig.m_first) { continue; } } if (!pid.Contains(orig.m_buildingID)) // 完全被遮挡的建筑物面 2019.1.2 { continue; } Polygon poly = new Polygon(ref orig); if (poly.clip(ref beam) == Polygon.ClipResult.CLIP_VANISHED) { continue; } if (poly.getArea() < EPS_DEGENERATE_POLYGON_AREA) { continue; } Beam b = new Beam(ref imgSource, ref poly); SolutionNode node = new SolutionNode(); node.m_polygon = orig; node.m_clipedPolygon = poly; node.m_parent = parentIndex; m_solutionNodes.Add(node); buildBeamTree1(ref imgSource, ref target, ref b, order + 1, m_solutionNodes.Count - 1); } }
// 建立 beam 树,得到 m_solutionNodes,不考虑遮挡 // 存储每个 beam 节点中离目标点最近的 beam 侧面 public void solveRecursive(ref Vector3 source, ref Vector3 target, ref Beam beam, int order, int parentIndex) { m_failPlanes.Add(new Vector4(getFailPlane(ref beam, ref target))); // 离目标点最近的面 if (order >= m_maximumOrder) { return; } List <Polygon> polygons = new List <Polygon>(); m_room.getKD().beamCast(ref beam, ref polygons); for (int i = (int)polygons.Count - 1; i >= 0; i--) // 当前 KD 节点中包含的所有多边形 { Polygon orig = polygons[i]; Vector3 imgSource = Vector4.mirror(ref source, orig.getPleq()); if (parentIndex > 0) // 有父 beam,跳过一些特殊情况 { Polygon ppoly = m_solutionNodes[parentIndex].m_polygon; if (orig.m_id == ppoly.m_id) // 如果与上一个面是同一个面,跳过 { continue; } Vector3 testSource = Vector4.mirror(ref imgSource, ppoly.getPleq()); if ((source - testSource).length() < EPS_SIMILAR_PATHS) // 如果与上一个源相距太近 { continue; } } else // 2018.12.11 被遮挡的面不构成初级 beam { if (!orig.m_first) { continue; } } Polygon poly = new Polygon(ref orig); if (poly.clip(ref beam) == Polygon.ClipResult.CLIP_VANISHED) { continue; } if (poly.getArea() < EPS_DEGENERATE_POLYGON_AREA) { continue; } Beam b = new Beam(ref imgSource, ref poly); SolutionNode node = new SolutionNode(); node.m_polygon = orig; //node.m_clipedPolygon = poly; node.m_parent = parentIndex; m_solutionNodes.Add(node); solveRecursive(ref imgSource, ref target, ref b, order + 1, m_solutionNodes.Count - 1); //if (order == 0) // Console.WriteLine("building beam tree.. {0}% ({1}) {2}\r", 100 - (float)i / (float)polygons.Count() * 100, m_solutionNodes.Count, m_node++); } //if (order == 0) //{ // Console.WriteLine("{0}", m_level++); //} }
public void beamTracing() { int numProc = 0; int numTested = 0; Vector3 source = m_source.getPosition(); Vector3 target = m_listener.getPosition(); m_paths.Clear(); // 只有当发射源改变了才会重新建立beam if (m_solutionNodes.Count == 0 || m_cachedSource.x != source.x || m_cachedSource.y != source.y || m_cachedSource.z != source.z) // target 改变后不影响 { clearCache(); SolutionNode root = new SolutionNode(); // beam 根节点 root.m_polygon = null; root.m_parent = -1; m_solutionNodes.Add(root); // 记录障碍物面及父 beam id DateTime t0 = DateTime.Now; Beam beam = new Beam(); buildBeamTree1(ref source, ref target, ref beam, 0, 0); // 得到 m_solutionNodes,m_failPlanes //solveRecursive(ref source, ref target, ref beam, 0, 0); // 得到 m_solutionNodes,m_failPlanes DateTime t1 = DateTime.Now; Console.WriteLine("束树建立时间:{0} s", (t1 - t0).TotalMilliseconds / 1000); Console.WriteLine(string.Format("束树节点总数:{0}", m_solutionNodes.Count)); m_cachedSource.x = source.x; m_cachedSource.y = source.y; m_cachedSource.z = source.z; // 设置桶的数量 // numBuckets <= m_s//olutionNodes.size() int numBuckets = (m_solutionNodes.Count + DISTANCE_SKIP_BUCKET_SIZE - 1) / DISTANCE_SKIP_BUCKET_SIZE; m_distanceSkipCache = new List <Vector4>(); for (int i = 0; i < numBuckets; i++) { m_distanceSkipCache.Add(new Vector4(0, 0, 0, 0)); } } int n = m_solutionNodes.Count; int nb = (m_solutionNodes.Count + DISTANCE_SKIP_BUCKET_SIZE - 1) / DISTANCE_SKIP_BUCKET_SIZE; // numBuckets List <Vector4> skipSphere = m_distanceSkipCache; for (int b = 0; b < nb; b++) { Vector4 fc = skipSphere[b]; Vector3 r = target - new Vector3(fc.x, fc.y, fc.z); // 与障碍物的距离 if (r.lengthSqr() < fc.w) // 接收点位于忽略球内,忽略所有路径测试。 { continue; } float maxdot = 0; numProc++; int imn = b * DISTANCE_SKIP_BUCKET_SIZE; // 第 b 个桶 int imx = imn + DISTANCE_SKIP_BUCKET_SIZE; if (imx > n) { imx = n; } for (int i = imn; i < imx; i++) { float d = Vector4.dot(ref target, m_failPlanes[i]); if (d >= 0) // 在失败面的前面,也就是在 beam 面的后面,可能有合法路径 { Vector4 failPlane = m_failPlanes[i]; validatePath(ref source, ref target, i, ref failPlane); // 验证路径,更新 m_failPlanes[i],m_path m_failPlanes[i] = failPlane; int cnt = m_paths.Count; numTested++; } if (i == imn || d > maxdot) { maxdot = d; } } if (maxdot < 0) // 桶中的所有节点都失败了,便可计算失败面到接收点的最短距离,作为半径,而接收点为球心 { m_distanceSkipCache[b].set(target.x, target.y, target.z, maxdot * maxdot); } } m_pathFirstSet.Clear(); }