Example #1
0
 public SQuantizedExtent3D Convert(Extent3D extent)
 {
     var e = new Extent3D(
         (extent.GetMinPoint3D() - Offset) / ScaleFactor,
         (extent.GetMaxPoint3D() - Offset) / ScaleFactor
     );
     return new SQuantizedExtent3D(e);
 }
Example #2
0
 public PointCloudBinarySource(FileHandlerBase file, long count, Extent3D extent, SQuantization3D quantization, long dataOffset, short pointSizeBytes)
     : base(file)
 {
     m_count = count;
     m_extent = extent;
     m_quantization = quantization;
     m_pointDataOffset = dataOffset;
     m_pointSizeBytes = pointSizeBytes;
     m_quantizedExtent = quantization.Convert(m_extent);
 }
        public PointCloudBinarySourceComposite(FileHandlerBase file, Extent3D extent, IPointCloudBinarySource[] sources)
            : base(file)
        {
            m_sources = sources;

            // verify that they are compatible

            m_count = m_sources.Sum(s => s.Count);
            m_extent = extent;
            m_quantization = m_sources[0].Quantization;
            m_pointSizeBytes = m_sources[0].PointSizeBytes;
            m_quantizedExtent = m_quantization.Convert(m_extent);
        }
Example #4
0
        public static void CopyToUnquantized(this Grid<int> target, Grid<float> output, Quantization3D quantization, Extent3D extent)
        {
            var data0 = target.Data;
            var data1 = output.Data;

            var scaleFactorZ = (float)quantization.ScaleFactorZ;
            var adjustedOffset = (float)(extent != null ? quantization.OffsetZ - extent.MinZ : quantization.OffsetZ);

            // ">" zero is not quite what I want here
            // it could lose some min values (not important for now)
            for (int y = 0; y < target.SizeY; y++)
                for (int x = 0; x < target.SizeX; x++)
                    if (data0[y, x] != target.FillVal)
                        data1[y, x] = data0[y, x] * scaleFactorZ + adjustedOffset;
        }
Example #5
0
        public LASFile(string path, LASHeader header, LASVLR[] vlrs, LASEVLR[] evlrs)
            : base(path)
        {
            m_header = header;
            m_vlrs = vlrs;
            m_evlrs = evlrs;

            using (var stream = File.Create(FilePath))
            {
                using (var writer = new FlexibleBinaryWriter(stream))
                {
                    header.Serialize(writer);
                }

                //header.WriteVLRs(stream, vlrs);
            }

            m_extent = m_header.Extent;
        }
Example #6
0
        public LASFile(string path)
            : base(path)
        {
            if (Exists)
            {
                try
                {
                    using (var stream = StreamManager.OpenReadStream(FilePath))
                    {
                        using (var reader = new FlexibleBinaryReader(stream))
                        {
                            m_header = reader.ReadLASHeader();
                        }

                        m_vlrs = m_header.ReadVLRs(stream);
                        m_evlrs = m_header.ReadEVLRs(stream);
                    }

                    m_extent = m_header.Extent;
                }
                catch { }
            }
        }
Example #7
0
        public void Initialize(Extent3D extent, int numPointsToProcess)
        {
            double SQRT3 = Math.Sqrt(3);

            //create one big Triangle_t aka. supertriangle
            //Make the bounding box slightly bigger,
            //actually no need for this if coming from streaming delaunay side

            m_extent = extent;

            // compute the supertriangle vertices, clockwise order, check the math
            m_superA = new DelaunayPoint(extent.MinX - extent.RangeY * SQRT3 / 3.0f, extent.MinY, extent.MinZ, numPointsToProcess);
            m_superB = new DelaunayPoint(extent.MidpointX, extent.MaxY + extent.RangeX * SQRT3 * 0.5f, extent.MinZ, numPointsToProcess + 1);
            m_superC = new DelaunayPoint(extent.MaxX + extent.RangeY * SQRT3 / 3.0f, extent.MinY, extent.MinZ, numPointsToProcess + 2);

            //create the super Triangle_t
            m_delaunayGraph = new Triangle(m_superA, m_superB, m_superC);

            //keep track of the current Triangle_t
            m_currentTriangle = m_delaunayGraph;

            m_newTriangles = new List<Triangle>();
            m_outputTriangles = new List<int>();
        }
Example #8
0
        public unsafe PointCloudBinarySource ConvertTextToBinary(string binaryPath, ProgressManager progressManager)
        {
            short pointSizeBytes = 3 * sizeof(double);

            double minX = 0, minY = 0, minZ = 0;
            double maxX = 0, maxY = 0, maxZ = 0;
            int pointCount = 0;

            using (var process = progressManager.StartProcess("ConvertTextToBinary"))
            {
                BufferInstance inputBuffer = process.AcquireBuffer(true);
                BufferInstance outputBuffer = process.AcquireBuffer(true);

                int pointsPerBuffer = outputBuffer.Length / pointSizeBytes;
                int usableBytesPerBuffer = pointsPerBuffer * pointSizeBytes;

                byte* inputBufferPtr = inputBuffer.DataPtr;
                byte* outputBufferPtr = outputBuffer.DataPtr;

                int bufferIndex = 0;
                int skipped = 0;

                using (var inputStream = StreamManager.OpenReadStream(FilePath))
                {
                    long inputLength = inputStream.Length;
                    long estimatedOutputLength = inputLength;

                    using (var outputStream = StreamManager.OpenWriteStream(binaryPath, estimatedOutputLength, 0, true))
                    {
                        int bytesRead;
                        int readStart = 0;

                        while ((bytesRead = inputStream.Read(inputBuffer.Data, readStart, inputBuffer.Length - readStart)) > 0)
                        {
                            bytesRead += readStart;
                            readStart = 0;
                            int i = 0;

                            while (i < bytesRead)
                            {
                                // identify line start
                                while (i < bytesRead && (inputBufferPtr[i] == '\r' || inputBufferPtr[i] == '\n'))
                                {
                                    ++i;
                                }

                                int lineStart = i;

                                // identify line end
                                while (i < bytesRead && inputBufferPtr[i] != '\r' && inputBufferPtr[i] != '\n')
                                {
                                    ++i;
                                }

                                // handle buffer overlap
                                if (i == bytesRead)
                                {
                                    Array.Copy(inputBuffer.Data, lineStart, inputBuffer.Data, 0, i - lineStart);
                                    readStart = i - lineStart;
                                    break;
                                }

                                // this may get overwritten if this is not a valid parse
                                double* p = (double*)(outputBufferPtr + bufferIndex);

                                if (!ParseXYZFromLine(inputBufferPtr, lineStart, i, p))
                                {
                                    ++skipped;
                                    continue;
                                }

                                if (pointCount == 0)
                                {
                                    minX = maxX = p[0];
                                    minY = maxY = p[1];
                                    minZ = maxZ = p[2];
                                }
                                else
                                {
                                    if (p[0] < minX) minX = p[0];
                                    else if (p[0] > maxX) maxX = p[0];
                                    if (p[1] < minY) minY = p[1];
                                    else if (p[1] > maxY) maxY = p[1];
                                    if (p[2] < minZ) minZ = p[2];
                                    else if (p[2] > maxZ) maxZ = p[2];
                                }

                                bufferIndex += pointSizeBytes;
                                ++pointCount;

                                // write usable buffer chunk
                                if (usableBytesPerBuffer == bufferIndex)
                                {
                                    outputStream.Write(outputBuffer.Data, 0, bufferIndex);
                                    bufferIndex = 0;
                                }
                            }

                            if (!process.Update((float)inputStream.Position / inputLength))
                                break;
                        }

                        // write remaining buffer
                        if (bufferIndex > 0)
                            outputStream.Write(outputBuffer.Data, 0, bufferIndex);
                    }
                }

                process.Log("Skipped {0} lines", skipped);
                process.LogTime("Copied {0:0,0} points", pointCount);
            }

            var extent = new Extent3D(minX, minY, minZ, maxX, maxY, maxZ);

            var source = new PointCloudBinarySource(this, pointCount, extent, null, 0, pointSizeBytes);

            return source;
        }
Example #9
0
        public LASHeader(BinaryReader reader)
        {
            long length = reader.BaseStream.Length;

            if (length < c_minHeaderSize[LASVersion.LAS_1_0])
                throw new OpenFailedException("Invalid format: header too short");

            if (Encoding.ASCII.GetString(reader.ReadBytes(FILE_SIGNATURE.Length)) != FILE_SIGNATURE)
                throw new OpenFailedException("Invalid format: signature does not match");

            m_fileSourceID          = reader.ReadUInt16();

            m_globalEncoding        = reader.ReadLASGlobalEncoding();
            m_projectID             = reader.ReadLASProjectID();
            m_version               = reader.ReadLASVersionInfo();

            m_systemIdentifier      = reader.ReadBytes(32).ToAsciiString();
            m_generatingSoftware    = reader.ReadBytes(32).ToAsciiString();
            m_fileCreationDayOfYear = reader.ReadUInt16();
            m_fileCreationYear      = reader.ReadUInt16();

            m_headerSize            = reader.ReadUInt16();
            m_offsetToPointData     = reader.ReadUInt32();

            ushort minHeaderSize = c_minHeaderSize[m_version.Version];
            if (length < minHeaderSize)
                throw new OpenFailedException("Invalid format: header too short for version");
            if(minHeaderSize > m_headerSize)
                throw new OpenFailedException("Invalid format: header size incorrect");

            m_numberOfVariableLengthRecords = reader.ReadUInt32();
            m_pointDataRecordFormat         = reader.ReadByte();
            m_pointDataRecordLength         = reader.ReadUInt16();
            m_legacyNumberOfPointRecords    = reader.ReadUInt32();
            m_legacyNumberOfPointsByReturn  = reader.ReadUInt32Array(5);

            m_quantization = reader.ReadSQuantization3D();
            m_extent       = reader.ReadExtent3D();

            if (m_version.Version >= LASVersion.LAS_1_3)
            {
                m_startOfWaveformDataPacketRecord = reader.ReadUInt64();
            }

            if (m_version.Version >= LASVersion.LAS_1_4)
            {
                m_startOfFirstExtendedVariableLengthRecord = reader.ReadUInt64();
                m_numberOfExtendedVariableLengthRecords    = reader.ReadUInt32();
                m_numberOfPointRecords                     = reader.ReadUInt64();
                m_numberOfPointsByReturn                   = reader.ReadUInt64Array(15);
            }
            else
            {
                m_numberOfPointRecords = m_legacyNumberOfPointRecords;
                m_numberOfPointsByReturn = new ulong[15];
                for (int i = 0; i < m_legacyNumberOfPointsByReturn.Length; i++)
                    m_numberOfPointsByReturn[i] = m_legacyNumberOfPointsByReturn[i];
            }

            // This doesn't apply to LAZ files
            //ulong pointDataRegionLength = (ulong)length - m_offsetToPointData;
            //if (pointDataRegionLength < m_pointDataRecordLength * PointCount)
            //    throw new Exception("Invalid format: point data region is not the expected size");
        }
Example #10
0
        /// <summary>
        /// This will only work if point format, point length, offset, and scale are identical.
        /// </summary>
        public LASHeader(LASHeader[] headers, LASVLR[] vlrs, LASEVLR[] evlrs)
        {
            var header = headers[0];
            var extent = headers.Select(h => h.m_extent).Union3D();

            var points = (ulong)headers.Sum(h => (long)h.m_numberOfPointRecords);
            var pointsByReturn = new ulong[15];
            for (var i = 0; i < pointsByReturn.Length; i++)
            {
                pointsByReturn[i] = (ulong)headers.Sum(h => (long)h.m_numberOfPointsByReturn[i]);
            }

            uint legacyPoints = 0;
            uint[] legacyPointsByReturn;

            if (points > uint.MaxValue)
            {
                legacyPoints = 0;
                legacyPointsByReturn = new uint[5];
            }
            else
            {
                legacyPoints = (uint)points;
                legacyPointsByReturn = pointsByReturn.Take(5).Select(c => (uint)c).ToArray();
            }

            m_fileSourceID = header.m_fileSourceID;

            m_globalEncoding = header.m_globalEncoding;
            m_projectID = header.m_projectID;
            m_version = LASVersionInfo.Create(LASVersion.LAS_1_4);

            m_systemIdentifier = header.m_systemIdentifier;
            m_generatingSoftware = header.m_generatingSoftware;
            m_fileCreationDayOfYear = header.m_fileCreationDayOfYear;
            m_fileCreationYear = header.m_fileCreationYear;

            m_headerSize = c_minHeaderSize[LASVersion.LAS_1_4];
            m_offsetToPointData = m_headerSize + (uint)vlrs.Sum(vlr => vlr.Length);

            m_numberOfVariableLengthRecords = (uint)vlrs.Length;
            m_pointDataRecordFormat = header.m_pointDataRecordFormat;
            m_pointDataRecordLength = header.m_pointDataRecordLength;

            if (points > uint.MaxValue)
            {
                m_legacyNumberOfPointRecords = 0;
                m_legacyNumberOfPointsByReturn = new uint[5];
            }
            else
            {
                m_legacyNumberOfPointRecords = legacyPoints;
                m_legacyNumberOfPointsByReturn = legacyPointsByReturn;
            }

            m_quantization = header.m_quantization;
            m_extent = extent;

            m_startOfWaveformDataPacketRecord = 0;

            m_startOfFirstExtendedVariableLengthRecord = m_offsetToPointData + (points * m_pointDataRecordLength);
            m_numberOfExtendedVariableLengthRecords = (uint)evlrs.Length;
            m_numberOfPointRecords = points;

            m_numberOfPointsByReturn = pointsByReturn;
        }
        public static System.Windows.Media.Media3D.MeshGeometry3D GenerateMesh(this PointCloudTileSource source, Grid<float> grid, Extent3D distributionExtent, bool showBackFaces)
        {
            // subtract midpoint to center around (0,0,0)
            Extent3D centeringExtent = source.Extent;
            Point3D centerOfMass = source.CenterOfMass;
            double centerOfMassMinusMin = centerOfMass.Z - centeringExtent.MinZ;

            var positions = new System.Windows.Media.Media3D.Point3DCollection(grid.CellCount);
            var indices = new System.Windows.Media.Int32Collection(2 * (grid.SizeX - 1) * (grid.SizeY - 1));

            float fillVal = grid.FillVal;

            for (int x = 0; x < grid.SizeX; x++)
            {
                for (int y = 0; y < grid.SizeY; y++)
                {
                    double value = grid.Data[x, y] - centerOfMassMinusMin;

                    double xCoord = ((double)x / grid.SizeX) * distributionExtent.RangeX + distributionExtent.MinX - distributionExtent.MidpointX;
                    double yCoord = ((double)y / grid.SizeY) * distributionExtent.RangeY + distributionExtent.MinY - distributionExtent.MidpointY;

                    xCoord += (distributionExtent.MidpointX - centeringExtent.MidpointX);
                    yCoord += (distributionExtent.MidpointY - centeringExtent.MidpointY);

                    var point = new System.Windows.Media.Media3D.Point3D(xCoord, yCoord, value);
                    positions.Add(point);

                    if (x > 0 && y > 0)
                    {
                        // add two triangles
                        int currentPosition = x * grid.SizeY + y;
                        int topPosition = currentPosition - 1;
                        int leftPosition = currentPosition - grid.SizeY;
                        int topleftPosition = leftPosition - 1;

                        if (grid.Data[x - 1, y] != fillVal && grid.Data[x, y - 1] != fillVal)
                        {
                            if (grid.Data[x, y] != fillVal)
                            {
                                indices.Add(leftPosition);
                                indices.Add(topPosition);
                                indices.Add(currentPosition);

                                if (showBackFaces)
                                {
                                    indices.Add(leftPosition);
                                    indices.Add(currentPosition);
                                    indices.Add(topPosition);
                                }
                            }

                            if (grid.Data[x - 1, y - 1] != fillVal)
                            {
                                indices.Add(topleftPosition);
                                indices.Add(topPosition);
                                indices.Add(leftPosition);

                                if (showBackFaces)
                                {
                                    indices.Add(topleftPosition);
                                    indices.Add(leftPosition);
                                    indices.Add(topPosition);
                                }
                            }
                        }
                    }
                }
            }

            var normals = new System.Windows.Media.Media3D.Vector3DCollection(positions.Count);

            for (int i = 0; i < positions.Count; i++)
                normals.Add(new System.Windows.Media.Media3D.Vector3D(0, 0, 0));

            for (int i = 0; i < indices.Count; i += 3)
            {
                int index1 = indices[i];
                int index2 = indices[i + 1];
                int index3 = indices[i + 2];

                System.Windows.Media.Media3D.Vector3D side1 = positions[index1] - positions[index3];
                System.Windows.Media.Media3D.Vector3D side2 = positions[index1] - positions[index2];
                System.Windows.Media.Media3D.Vector3D normal = System.Windows.Media.Media3D.Vector3D.CrossProduct(side1, side2);

                normals[index1] += normal;
                normals[index2] += normal;
                normals[index3] += normal;
            }

            for (int i = 0; i < normals.Count; i++)
            {
                if (normals[i].Length > 0)
                {
                    var normal = normals[i];
                    normal.Normalize();

                    // the fact that this is necessary means I am doing something wrong
                    if (normal.Z < 0)
                        normal.Negate();

                    normals[i] = normal;
                }
            }

            var geometry = new System.Windows.Media.Media3D.MeshGeometry3D
            {
                Positions = positions,
                TriangleIndices = indices,
                Normals = normals
            };

            return geometry;
        }
 public static System.Windows.Media.Media3D.MeshGeometry3D GenerateMesh(this PointCloudTileSource source, Grid<float> grid, Extent3D distributionExtent)
 {
     return GenerateMesh(source, grid, distributionExtent, false);
 }
Example #13
0
 public LAZBinarySource(FileHandlerBase file, long count, Extent3D extent, SQuantization3D quantization, long dataOffset, short pointSizeBytes)
     : base(file, count, extent, quantization, dataOffset, pointSizeBytes)
 {
     m_handler = (LAZFile)file;
 }
Example #14
0
        public unsafe void ComputeExtent(ProgressManager progressManager)
        {
            using (var process = progressManager.StartProcess("CalculateLASExtent"))
            {
                short pointSizeBytes = PointSizeBytes;

                int minX = 0, minY = 0, minZ = 0;
                int maxX = 0, maxY = 0, maxZ = 0;

                foreach (var chunk in GetBlockEnumerator(process))
                {
                    if (minX == 0 && maxX == 0)
                    {
                        var p = (SQuantizedPoint3D*)chunk.PointDataPtr;

                        minX = maxX = (*p).X;
                        minY = maxY = (*p).Y;
                        minZ = maxZ = (*p).Z;
                    }

                    byte* pb = chunk.PointDataPtr;
                    while (pb < chunk.PointDataEndPtr)
                    {
                        var p = (SQuantizedPoint3D*)pb;

                        if ((*p).X < minX) minX = (*p).X; else if ((*p).X > maxX) maxX = (*p).X;
                        if ((*p).Y < minY) minY = (*p).Y; else if ((*p).Y > maxY) maxY = (*p).Y;
                        if ((*p).Z < minZ) minZ = (*p).Z; else if ((*p).Z > maxZ) maxZ = (*p).Z;

                        pb += pointSizeBytes;
                    }

                    if (!process.Update(chunk))
                        break;
                }

                var quantizedExtent = new SQuantizedExtent3D(minX, minY, minZ, maxX, maxY, maxZ);
                m_extent = m_header.Quantization.Convert(quantizedExtent);

                process.LogTime("Traversed {0:0,0} points", Count);
            }
        }