Example #1
0
        /// <summary>
        /// Returns new tree with regenerated normals using given estimateNormals function.
        /// </summary>
        private static PointSetNode RegenerateNormals(this PointSetNode self,
                                                      Func <IList <V3d>, IList <V3f> > estimateNormals,
                                                      Action callback, CancellationToken ct
                                                      )
        {
            if (self == null)
            {
                throw new ArgumentNullException(nameof(self));
            }

            ct.ThrowIfCancellationRequested();

            callback?.Invoke();

            if (self.IsLeaf)
            {
                // generate and store normals
                var ns   = estimateNormals(self.PositionsAbsolute).ToArray();
                var nsId = Guid.NewGuid();
                self.Storage.Add(nsId, ns, ct);

                // create node with new normals and LoD normals
                var r = self.WithNormals(nsId).WithLod();

                return(r);
            }

            if (self.Subnodes == null || self.Subnodes.Length != 8)
            {
                throw new InvalidOperationException();
            }

            var subcells           = self.Subnodes.Map(x => x?.Value.RegenerateNormals(estimateNormals, callback, ct));
            var subcellsTotalCount = (long)subcells.Sum(x => x?.PointCountTree);
            var octreeSplitLimit   = self.LodPositions.Value.Length;

            var fractions = new double[8].SetByIndex(
                ci => subcells[ci] != null ? (subcells[ci].PointCountTree / (double)subcellsTotalCount) : 0.0
                );
            var remainder = 0.1;
            var counts    = fractions.Map(x =>
            {
                var fn    = octreeSplitLimit * x + remainder;
                var n     = (int)fn;
                remainder = fn - n;
                return(n);
            });
            var e = octreeSplitLimit - counts.Sum();

            if (e != 0)
            {
                throw new InvalidOperationException();
            }

            // generate LodNormals ...
            var lodNs = new V3f[octreeSplitLimit];
            var i     = 0;

            for (var ci = 0; ci < 8; ci++)
            {
                if (counts[ci] == 0)
                {
                    continue;
                }
                var subcell = subcells[ci];
                if (subcell == null)
                {
                    continue;
                }

                var subns = subcell.LodNormals.Value;

                var jmax = subns.Length;
                var dj   = (jmax + 0.49) / counts[ci];
                var oldI = i;
                for (var j = 0.0; j < jmax; j += dj)
                {
                    var jj = (int)j;
                    lodNs[i] = subns[jj];
                    i++;
                }
            }

            // store LoD data ...
            var lodNsId = Guid.NewGuid();

            self.Storage.Add(lodNsId, lodNs, ct);

            var result = self.WithLod(self.LodPositionsId, self.LodColorsId, lodNsId, self.LodIntensitiesId, self.LodKdTreeId, subcells);

            return(result);
        }
Example #2
0
        /// <summary>
        /// </summary>
        private static PointSetNode GenerateLod(this PointSetNode self, long octreeSplitLimit, Action callback, CancellationToken ct)
        {
            if (self == null)
            {
                throw new ArgumentNullException(nameof(self));
            }

            ct.ThrowIfCancellationRequested();

            callback?.Invoke();

            if (self.IsLeaf)
            {
                return(self.WithLod());
            }

            if (self.Subnodes == null || self.Subnodes.Length != 8)
            {
                throw new InvalidOperationException();
            }

            var subcells           = self.Subnodes.Map(x => x?.Value.GenerateLod(octreeSplitLimit, callback, ct));
            var subcellsTotalCount = (long)subcells.Sum(x => x?.PointCountTree);

            var needsCs = subcells.Any(x => x != null ? (x.HasColors || x.HasLodColors) : false);
            var needsNs = subcells.Any(x => x != null ? (x.HasNormals || x.HasLodNormals) : false);
            var needsIs = subcells.Any(x => x != null ? (x.HasIntensities || x.HasLodIntensities) : false);

            var fractions = new double[8].SetByIndex(
                ci => subcells[ci] != null ? (subcells[ci].PointCountTree / (double)subcellsTotalCount) : 0.0
                );
            var remainder = 0.1;
            var counts    = fractions.Map(x =>
            {
                var fn    = octreeSplitLimit * x + remainder;
                var n     = (int)fn;
                remainder = fn - n;
                return(n);
            });
            var e = octreeSplitLimit - counts.Sum();

            if (e != 0)
            {
                throw new InvalidOperationException();
            }

            // generate LoD data ...
            var lodPs = new V3f[octreeSplitLimit];
            var lodCs = needsCs ? new C4b[octreeSplitLimit] : null;
            var lodNs = needsNs ? new V3f[octreeSplitLimit] : null;
            var lodIs = needsIs ? new int[octreeSplitLimit] : null;
            var i     = 0;

            for (var ci = 0; ci < 8; ci++)
            {
                if (counts[ci] == 0)
                {
                    continue;
                }
                var subcell = subcells[ci];
                if (subcell == null)
                {
                    continue;
                }

                var subps = subcell.IsLeaf ? subcell.Positions.Value : subcell.LodPositions.Value;
                var subcs = needsCs ? (subcell.IsLeaf ? subcell.Colors.Value : subcell.LodColors.Value) : null;
                var subns = needsNs ? (subcell.IsLeaf ? subcell.Normals.Value : subcell.LodNormals.Value) : null;
                var subis = needsIs ? (subcell.IsLeaf ? subcell.Intensities.Value : subcell.LodIntensities.Value) : null;

                var jmax = subps.Length;
                var dj   = (jmax + 0.49) / counts[ci];
                var oldI = i;
                for (var j = 0.0; j < jmax; j += dj)
                {
                    var jj = (int)j;
                    lodPs[i] = (V3f)(((V3d)subps[jj] + subcell.Center) - self.Center);
                    if (needsCs)
                    {
                        lodCs[i] = subcs[jj];
                    }
                    if (needsNs)
                    {
                        lodNs[i] = subns[jj];
                    }
                    if (needsIs)
                    {
                        lodIs[i] = subis[jj];
                    }
                    i++;
                }
            }
            var lodKd = lodPs.BuildKdTree();

            // store LoD data ...
            var lodPsId = Guid.NewGuid();

            self.Storage.Add(lodPsId, lodPs, ct);

            var lodKdId = Guid.NewGuid();

            self.Storage.Add(lodKdId, lodKd.Data, ct);

            var lodCsId = needsCs ? (Guid?)Guid.NewGuid() : null;

            if (needsCs)
            {
                self.Storage.Add(lodCsId.Value, lodCs, ct);
            }

            var lodNsId = needsNs ? (Guid?)Guid.NewGuid() : null;

            if (needsNs)
            {
                self.Storage.Add(lodNsId.Value, lodNs, ct);
            }

            var lodIsId = needsIs ? (Guid?)Guid.NewGuid() : null;

            if (needsIs)
            {
                self.Storage.Add(lodIsId.Value, lodIs, ct);
            }

            var result = self.WithLod(lodPsId, lodCsId, lodNsId, lodIsId, lodKdId, subcells);

            return(result);
        }
Example #3
0
        /// <summary>
        /// </summary>
        public static PointSetNode Delete(this PointSetNode node,
                                          Func <PointSetNode, bool> isNodeFullyInside,
                                          Func <PointSetNode, bool> isNodeFullyOutside,
                                          Func <V3d, bool> isPositionInside,
                                          CancellationToken ct
                                          )

        {
            if (node == null)
            {
                return(null);
            }
            if (isNodeFullyInside(node))
            {
                return(null);
            }
            if (isNodeFullyOutside(node))
            {
                return(node);
            }

            if (node.IsLeaf)
            {
                Guid?newPsId = null;
                Guid?newCsId = null;
                Guid?newNsId = null;
                Guid?newIsId = null;
                Guid?newKdId = null;

                if (!node.HasPositions)
                {
                    throw new InvalidOperationException();
                }

                var ps            = new List <V3f>();
                var cs            = node.HasColors ? new List <C4b>() : null;
                var ns            = node.HasNormals ? new List <V3f>() : null;
                var js            = node.HasIntensities ? new List <int>() : null;
                var oldPsAbsolute = node.PositionsAbsolute;
                var oldPs         = node.Positions.Value;
                var oldCs         = node.Colors?.Value;
                var oldNs         = node.Normals?.Value;
                var oldIs         = node.Intensities?.Value;
                for (var i = 0; i < oldPsAbsolute.Length; i++)
                {
                    if (!isPositionInside(oldPsAbsolute[i]))
                    {
                        ps.Add(oldPs[i]);
                        if (oldCs != null)
                        {
                            cs.Add(oldCs[i]);
                        }
                        if (oldNs != null)
                        {
                            ns.Add(oldNs[i]);
                        }
                        if (oldIs != null)
                        {
                            js.Add(oldIs[i]);
                        }
                    }
                }

                if (ps.Count > 0)
                {
                    newPsId = Guid.NewGuid();
                    var psa = ps.ToArray();
                    node.Storage.Add(newPsId.Value, psa, ct);

                    newKdId = Guid.NewGuid();
                    node.Storage.Add(newKdId.Value, psa.BuildKdTree().Data, ct);

                    if (node.HasColors)
                    {
                        newCsId = Guid.NewGuid();
                        node.Storage.Add(newCsId.Value, cs.ToArray(), ct);
                    }

                    if (node.HasNormals)
                    {
                        newNsId = Guid.NewGuid();
                        node.Storage.Add(newNsId.Value, ns.ToArray(), ct);
                    }

                    if (node.HasIntensities)
                    {
                        newIsId = Guid.NewGuid();
                        node.Storage.Add(newIsId.Value, js.ToArray(), ct);
                    }

                    var result = new PointSetNode(node.Cell, ps.Count, newPsId, newCsId, newKdId, newNsId, newIsId, node.Storage);
                    if (node.HasLodPositions)
                    {
                        result = result.WithLod();
                    }
                    return(result);
                }
                else
                {
                    return(null);
                }
            }
            else
            {
                Guid?newLodPsId = null;
                Guid?newLodCsId = null;
                Guid?newLodNsId = null;
                Guid?newLodIsId = null;
                Guid?newLodKdId = null;

                if (node.HasLodPositions)
                {
                    var ps = node.HasLodPositions ? new List <V3f>() : null;
                    var cs = node.HasLodColors ? new List <C4b>() : null;
                    var ns = node.HasLodNormals ? new List <V3f>() : null;
                    var js = node.HasLodIntensities ? new List <int>() : null;
                    var oldLodPsAbsolute = node.LodPositionsAbsolute;
                    var oldLodPs         = node.LodPositions.Value;
                    var oldLodCs         = node.LodColors?.Value;
                    var oldLodNs         = node.LodNormals?.Value;
                    var oldLodIs         = node.LodIntensities?.Value;
                    for (var i = 0; i < oldLodPsAbsolute.Length; i++)
                    {
                        if (!isPositionInside(oldLodPsAbsolute[i]))
                        {
                            ps.Add(oldLodPs[i]);
                            if (oldLodCs != null)
                            {
                                cs.Add(oldLodCs[i]);
                            }
                            if (oldLodNs != null)
                            {
                                ns.Add(oldLodNs[i]);
                            }
                            if (oldLodIs != null)
                            {
                                js.Add(oldLodIs[i]);
                            }
                        }
                    }

                    if (ps.Count > 0)
                    {
                        newLodPsId = Guid.NewGuid();
                        var psa = ps.ToArray();
                        node.Storage.Add(newLodPsId.Value, psa, ct);

                        newLodKdId = Guid.NewGuid();
                        node.Storage.Add(newLodKdId.Value, psa.BuildKdTree().Data, ct);

                        if (node.HasLodColors)
                        {
                            newLodCsId = Guid.NewGuid();
                            node.Storage.Add(newLodCsId.Value, cs.ToArray(), ct);
                        }

                        if (node.HasLodNormals)
                        {
                            newLodNsId = Guid.NewGuid();
                            node.Storage.Add(newLodNsId.Value, ns.ToArray(), ct);
                        }

                        if (node.HasLodIntensities)
                        {
                            newLodIsId = Guid.NewGuid();
                            node.Storage.Add(newLodIsId.Value, js.ToArray(), ct);
                        }
                    }
                }

                var newSubnodes = node.Subnodes.Map(n => n?.Value.Delete(isNodeFullyInside, isNodeFullyOutside, isPositionInside, ct));
                if (newSubnodes.All(n => n == null))
                {
                    return(null);
                }
                return(node.WithLod(newLodPsId, newLodCsId, newLodNsId, newLodIsId, newLodKdId, newSubnodes));
            }
        }