Revit二次开发之八叉树实现

在Revit二次开发过程中,常常需要需要按位置查找图元;例如查找某个图元邻近的图元,采用遍历过滤器的方法时间复杂度O(n),如果需要查找每个图元的邻近图元时间复杂度则可以达到O(n²)。采用八叉树查找则可将其时间复杂度降到O(logn)和O(nlogn),大大提高查找效率。

 public class OctTreeNode<T>
    {
        private XYZ _origin;
        /// <summary>
        /// 节点中心位置
        /// </summary>
        public XYZ Origin { get => _origin; }

        /// <summary>
        /// 是否为叶子节点
        /// </summary>
        public bool IsLeaf { get => this.Range <= Tolerance; }

        private double _range;
        /// <summary>
        /// 节点范围
        /// </summary>
        public double Range { get => _range; }

        private double _tolerance;
        /// <summary>
        /// 叶子节点精度值
        /// </summary>
        public double Tolerance { get => _tolerance; }

        private List<T> _items = null;
        /// <summary>
        /// 所有位于节点内的元素
        /// </summary>
        public IList<T> Items
        {
            get
            {
                if (_items == null)
                {
                    _items = new List<T>();
                }
                return _items;
            }
        }

        private OctTreeNode<T>[,,] _children = null;
        /// <summary>
        /// 子节点
        /// </summary>
        public OctTreeNode<T>[,,] Children
        {
            get
            {
                if (_children == null)
                {
                    _children = new OctTreeNode<T>[2, 2, 2];
                }
                return _children;
            }
        }
        private OctTreeNode<T> _parent = null;
        /// <summary>
        /// 父节点
        /// </summary>
        public OctTreeNode<T> Parent { get => _parent; set => _parent = value; }

        /// <summary>
        /// 使用默认值创建节点
        /// </summary>
        public OctTreeNode() : this(new XYZ(0, 0, 0), 1e14, 1e-6) { }

        /// <summary>
        /// 使用指定参数创建节点
        /// </summary>
        /// <param name="origin">节点中心位置</param>
        /// <param name="range">节点范围</param>
        /// <param name="tolerance">精度</param>
        public OctTreeNode(XYZ origin, double range, double tolerance)
        {
            this._origin = origin;
            this._range = range;
            this._tolerance = tolerance;
        }


        private OctTreeNode(OctTreeNode<T> parent, XYZ location)
        {
            int x_multiplier = location.X >= parent._origin.X ? 1 : -1;
            int y_multiplier = location.Y >= parent._origin.Y ? 1 : -1;
            int z_multiplier = location.Z >= parent._origin.Z ? 1 : -1;

            int x_index = location.X >= parent._origin.X ? 1 : 0;
            int y_index = location.Y >= parent._origin.Y ? 1 : 0;
            int z_index = location.Z >= parent._origin.Z ? 1 : 0;

            this._range = parent._range / 2;
            this._tolerance = parent._tolerance;
            this._origin = new XYZ(parent._origin.X + x_multiplier * parent._range / 4,
                parent._origin.Y + y_multiplier * parent._range / 4,
                parent._origin.Z + z_multiplier * parent._range / 4);
            this.Parent = parent;
            parent.Children[x_index, y_index, z_index] = this;
        }


        /// <summary>
        /// 获取叶子节点,如果没有则创建新的叶子节点
        /// </summary>
        /// <param name="location"></param>
        /// <returns></returns>
        private OctTreeNode<T> GetOrCreate_LeafNode(XYZ location)
        {
            var result = this;
            while (!result.IsLeaf)
            {
                result = result.Get_ChildNode(location) ?? new OctTreeNode<T>(result, location);
            }
            return result;
        }

        /// <summary>
        /// 获取叶子节点,如果没有则返回Null
        /// </summary>
        /// <param name="location"></param>
        /// <returns></returns>
        private OctTreeNode<T> Get_LeafNode(XYZ location)
        {
            var result = this;
            while (result != null && !result.IsLeaf)
            {
                result = result.Get_ChildNode(location);
            }

            return result;
        }
        /// <summary>
        /// 获取子节点
        /// </summary>
        /// <param name="location"></param>
        /// <returns></returns>
        private OctTreeNode<T> Get_ChildNode(XYZ location)
        {
            var x_index = location.X >= this._origin.X ? 1 : 0;
            var y_index = location.Y >= this._origin.Y ? 1 : 0;
            var z_index = location.Z >= this._origin.Z ? 1 : 0;
            return this.Children[x_index, y_index, z_index];
        }

        /// <summary>
        /// 坐标点及附加范围的任意部分是否在节点范围内
        /// </summary>
        /// <param name="point">坐标点</param>
        /// <param name="rangeX">X轴方向附加范围</param>
        /// <param name="rangeY">Y轴方向附加范围</param>
        /// <param name="rangeZ">Z轴方向附加范围</param>
        /// <returns></returns>
        private bool Is_Inside(XYZ point, double rangeX = 0, double rangeY = 0, double rangeZ = 0)
        {
            var distanceX = Math.Abs(point.X - this._origin.X);
            var distanceY = Math.Abs(point.Y - this._origin.Y);
            var distanceZ = Math.Abs(point.Z - this._origin.Z);
            return distanceX <= _range / 2 + rangeX / 2 &&
                distanceY <= _range / 2 + rangeY / 2 &&
                distanceZ <= _range / 2 + rangeZ / 2;
        }

        /// <summary>
        /// 将元素添加到对应位置
        /// </summary>
        /// <param name="item">要添加的元素</param>
        /// <param name="location">位置坐标</param>
        public void Add(T item, XYZ location)
        {
            if (this.IsLeaf)
            {
                this.Add(item);
            }
            else
            {
                this.GetOrCreate_LeafNode(location).Add(item);
            }
        }
        private void Add(T item)
        {
            this.Items.Add(item);
        }
        private bool Remove(T item)
        {
            return this.Items.Remove(item);
        }
        /// <summary>
        /// 将元素从对应位置移除
        /// </summary>
        /// <param name="item"></param>
        /// <param name="location"></param>
        public bool Remove(T item, XYZ location)
        {
            if (this.IsLeaf)
            {
                return this.Remove(item);
            }
            else
            {
                return (bool)this.Get_LeafNode(location)?.Remove(item);
            }
        }

        /// <summary>
        /// 移除所有元素
        /// </summary>
        public void Clear()
        {
            this.Items.Clear();
            this._children = null;
        }

        /// <summary>
        /// 查找指定区域内的元素
        /// </summary>
        /// <param name="coord">坐标位置</param>
        /// <param name="xRange">X轴方向范围</param>
        /// <param name="yRange">Y轴方向范围</param>
        /// <param name="zRange">Z轴方向范围</param>
        /// <returns></returns>
        public IEnumerable<T> Find(XYZ coord, double xRange = 0, double yRange = 0, double zRange = 0)
        {
            List<T> result = new List<T>();
            Queue<OctTreeNode<T>> nodes = new Queue<OctTreeNode<T>>(new OctTreeNode<T>[1] { this });

            while (nodes.Count > 0)
            {
                var currrent = nodes.Dequeue();
                if (currrent == null || !currrent.Is_Inside(coord, xRange, yRange, zRange))
                {
                    continue;
                }
                else if (!currrent.IsLeaf)
                {
                    foreach (var child in currrent.Children)
                    {
                        nodes.Enqueue(child);
                    }
                }
                else
                {
                    result.AddRange(currrent.Items);
                }
            }
            return result;
        }

        /// <summary>
        /// 获取所有元素
        /// </summary>
        /// <returns></returns>
        public IEnumerable<T> GetAll()
        {
            var result = new List<T>();
            var nodes = new Queue<OctTreeNode<T>>(new OctTreeNode<T>[1] { this });
            while (nodes.Count > 0)
            {
                var current = nodes.Dequeue();
                if (current == null) continue;
                result.AddRange(current.Items);
                if (!current.IsLeaf)
                {
                    foreach (var child in current.Children)
                    {
                        nodes.Enqueue(child);
                    }
                }
            }
            return result;
        }
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值