Extension Name E57_LEICA_Terrain_Classification XML namespace CLASS xmlns:class="http://www.libe57.org/E57_LEICA_Terrain_Classification.txt" Contact Aldo Facchin, Leica GeoSystems (aldo . facchin @ leica-geosystems.com) Stan Coleby, Cerisoft LLC (stan . coleby @ gmail.com) Contributors none. Version Last Modified Date: October 4, 2014 Revision: 1 Dependencies none. Overview This extension adds terrain classification codes to the point cloud data. This allows each point to be classified according to similar features. The classification codes are similar to LAS V1.4 definition. IP Status No known IP claims. New Fields none. New Fields none. New Fields none. New PointRecord Fields Element Name Type Description "class:classification" Integer Terrain Classification Code The classification code is an integer in the range of 0 to 255. Here is an example of typical classification codes: 0 None 1 Unclassified 2 Bare-earth Ground 3 Low Vegetation 4 Medium Vegetation 5 High Vegetation 6 Building 7 Noise (Low Point) 8 Reserved 9 Water 10 Rail 11 Road 12 Reserved Car? 13 Wire - Guard (Shield) 14 Wire - Conductor (Phase) 15 Transmission Tower 16 Wire-structure Connector 17 Bridge Deck 18 High Noise 19-63 Reserved 64-255 User definable "class:attribute" Integer Optional Classification Attribute Flags The classification attribute field is an 8-bit integer where each bit is a property of the point data. Here are the attributes assigned: bit 1 0x01 Synthetic The associated point was generated. bit 2 0x02 Key Point The point is a model key point. bit 3 0x04 Withheld The point should be omitted from modelling. bit 4 0x08 Overlap The point is in an overlap region. bit 5 0x10 Reserved bit 6 0x20 Reserved bit 7 0x40 Reserved bit 8 0x80 Reserved XML Example ... ... Sample Code ////////////////////////////////// // Writing Extension declaration// ////////////////////////////////// // Sample API or e57::Writer pWriter(...); pWriter.GetRawIMF().extensionsAdd("class","http://www.libe57.org/E57_LEICA_Terrain_Classification.txt"); // FoundationAPI _imf.extensionsAdd("class","http://www.libe57.org/E57_LEICA_Terrain_Classification.txt"); ... /////////////////////////////// // Write classification points ////////////////////////////// // Setup PointRecord prototype ////////////////////////////// // Sample API // call back function bool ProtoClassification( ImageFile imf, StructureNode proto) { proto.set("class:classification", IntegerNode(imf, 0, 0, 255)); proto.set("class:attribute", IntegerNode(imf, 0, 0, 255)); ... return true; }; // Setup main header e57::Data3D header; header.name = (char*) scanName; // Set the name of the scan ... // when registering a scan use the function pointer to the above ProtoClassification(). int scanIndex = pWriter.NewData3D(header, &ProtoClassification); ... //////////////////////////////////// // Foundation API StructureNode proto = StructureNode(imf_); ... proto.set("class:classification", IntegerNode(imf, 0, 0, 255)); proto.set("class:attribute", IntegerNode(imf, 0, 0, 255)); ... VectorNode codecs = VectorNode(imf_, true); CompressedVectorNode points = CompressedVectorNode(imf_, proto, codecs); scan.set("points", points); ////////////////////////// // Setup buffers ////////////////////////// // Sample API #define DATA_SIZE 1024 //buffer size; extern uint8_t * classificationData; extern uint8_t * attributeData; //call back function bool PointDataClassification( ImageFile imf, StructureNode proto, vector & sourceBuffers) { if(proto.isDefined("class:classification")) sourceBuffers.push_back(SourceDestBuffer(imf,"class:classification", classificationData, (unsigned) DATA_SIZE, true)); if(proto.isDefined("class:attribute")) sourceBuffers.push_back(SourceDestBuffer(imf,"class:attribute", attributeData, (unsigned) DATA_SIZE, true)); return true; } ... // setup the classification extension buffer classificationData = new uint8_t[DATA_SIZE]; if(classificationData == NULL) throw E57_EXCEPTION2(E57_ERROR_INTERNAL,"Error: allocation of memory failed (E57_ERROR_INTERNAL)"); attributeData = new uint8_t[DATA_SIZE]; if(attributeData == NULL) throw E57_EXCEPTION2(E57_ERROR_INTERNAL,"Error: allocation of memory failed (E57_ERROR_INTERNAL)"); //set up the compressedVectorWriter object e57::CompressedVectorWriter CVWriter = pWriter.SetUpData3DPointsData( scanIndex, //!< data block index given by the NewData3D DATA_SIZE, //!< size of each of the buffers given xData, //!< pointer to a buffer with the x data yData, //!< pointer to a buffer with the y data zData, //!< pointer to a buffer with the z data isInvalidData, //!< pointer to a buffer with the valid cartesian indication intData, //!< pointer to a buffer with the lidar return intesity isInvalidInt, //!< pointer to a buffer with the valid intensity indication redData, //!< pointer to a buffer with the color red data greenData, //!< pointer to a buffer with the color green data blueData, //!< pointer to a buffer with the color blue data isInvalidColor, //!< pointer to a buffer with the valid color indication rData, //!< pointer to a buffer with the range data aData, //!< pointer to a buffer with the azimuth data eData, //!< pointer to a buffer with the elevation data isInvalidSpherical, //!< pointer to a buffer with the valid spherical indication rowIndex, //!< pointer to a buffer with the rowIndex columnIndex, //!< pointer to a buffer with the columnIndex returnIndex, //!< pointer to a buffer with the returnIndex returnCount, //!< pointer to a buffer with the returnCount timeStamp, //!< pointer to a buffer with the timeStamp data isInvalidTime, //!< pointer to a buffer with the valid time indication &PointDataClassification); //!< call back pointer to adding extension buffers //////////////////////////////////// // Foundation API uint8_t * classificationData = new uint8_t[DATA_SIZE]; uint8_t * attributeData = new uint8_t[DATA_SIZE]; ... StructureNode scan(data3D_.get(dataIndex)); CompressedVectorNode points(scan.get("points")); StructureNode proto(points.prototype()); vector sourceBuffers; ... if(proto.isDefined("class:classification")) sourceBuffers.push_back(SourceDestBuffer(imf,"class:classification", classificationData, (unsigned) DATA_SIZE, true)); if(proto.isDefined("class:attribute")) sourceBuffers.push_back(SourceDestBuffer(imf,"class:attribute", attributeData, (unsigned) DATA_SIZE, true)); ... CompressedVectorWriter CVWriter = points.writer(sourceBuffers); ///////////////////////////////// // Both APIs // Write data ////////////////////////////// ... unsigned size; while(size = getYourData(..)) { for(long i = 0; i < DATA_SIZE; i++) { ... //get classification and load buffer classificationData[i] = getYourPointClassification(..); attributeData[i] = getYourPointAttribute(..); ... } CVWriter.write(size); } CVWriter.close(); /////////////////////////// //Read classification data ///////////////////////// // Sample API #define DATA_SIZE 1024 //buffer size; extern uint8_t * classificationData; extern uint8_t * attributeData; // call back function bool PointDataClassification( ImageFile imf, StructureNode proto, int protoIndex, vector & destBuffers) { ustring url; ustring name = proto.get(protoIndex).elementName(); NodeType type = proto.get(protoIndex).type(); bool scaled = type == E57_SCALED_INTEGER ? true : false; if(imf.extensionsLookupPrefix("class", url)) { if((name.compare("class:classification") == 0) && proto.isDefined("class:classification") && classificationData != NULL) ) { destBuffers.push_back(SourceDestBuffer(imf, "class:classification", classificationData, (unsigned) DATA_SIZE, true)); } if((name.compare("class:attribute") == 0) && proto.isDefined("class:attribute") && attributeData != NULL) ) { destBuffers.push_back(SourceDestBuffer(imf, "class:attribute", attributeData, (unsigned) DATA_SIZE, true)); } return true; } return false; } e57::Reader pReader(....); ... // setup the classification extension buffer ustring url; if (imf.extensionsLookupPrefix("class", url)) { classificationData = new uint8_t[(unsigned int) nSize]; if(classificationData == NULL) throw E57_EXCEPTION2(E57_ERROR_INTERNAL,"Error: allocation of memory failed (E57_ERROR_INTERNAL)"); memset(classificationData,0,(size_t)nSize); //clear array attributeData = new uint8_t[(unsigned int) nSize]; if(attributeData == NULL) throw E57_EXCEPTION2(E57_ERROR_INTERNAL,"Error: allocation of memory failed (E57_ERROR_INTERNAL)"); memset(attributeData,0,(size_t)nSize); //clear array } e57::CompressedVectorReader CVReader = pReader.SetUpData3DPointsData( scanIndex, //!< data block index given by the NewData3D nSize, //!< size of each of the buffers given xData, //!< pointer to a buffer with the x data yData, //!< pointer to a buffer with the y data zData, //!< pointer to a buffer with the z data isXYZInvalid, //!< pointer to a buffer with the valid indication intData, //!< pointer to a buffer with the lidar return intensity intInvalid, redData, //!< pointer to a buffer with the color red data greenData, //!< pointer to a buffer with the color green data blueData, //!< pointer to a buffer with the color blue data colorInvalid, rData, aData, eData, isRAEInvalid, rowIndex, columnIndex, returnIndex, returnCount, timeStamp, timeInvalid, &PointDataClassification //////////////////////////////////// // Foundation API uint8_t *classificationData = NULL; uint8_t *attributeData = NULL; ustring url; if (imf.extensionsLookupPrefix("class", url)) { classificationData = new uint8_t[DATA_SIZE]; attributeData = new uint8_t[DATA_SIZE]; } StructureNode scan(data3D_.get(dataIndex)); CompressedVectorNode points(scan.get("points")); StructureNode prototype(points.prototype()); ... int64_t protoCount = prototype.childCount(); int64_t protoIndex; vector destBuffers; for( protoIndex = 0; protoIndex < protoCount; protoIndex++) { ustring name = prototype.get(protoIndex).elementName(); NodeType type = prototype.get(protoIndex).type(); bool scaled = type == E57_SCALED_INTEGER ? true : false; ... ustring url; if((name.compare("class:classification") == 0) && imf.extensionsLookupPrefix("class", url) && proto.isDefined("class:classification") && (classificationData != NULL) ) destBuffers.push_back(SourceDestBuffer(imf, "class:classification", classificationData, (unsigned) DATA_SIZE, true)); if((name.compare("class:attribute") == 0) && imf.extensionsLookupPrefix("class", url) && proto.isDefined("class:attribute") && (attributeData != NULL) ) destBuffers.push_back(SourceDestBuffer(imf, "class:attribute", attributeData, (unsigned) DATA_SIZE, true)); ... } CompressedVectorReader CVReader = points.reader(destBuffers); ... ///////////////////////// // Both APIs // Read point data ///////////////////////// unsigned size = 0; while(size = CVReader.read()) { for(long i = 0; i < size; i++) { Point P(pCartesianX[i],pCartesianY[i],pCartesianZ[i]); ... if(classificationData) UCHAR classification = classificationData[i]; if(attributeData) UCHAR attribute = attributeData[i]; ... } } Issues none ASTM E57 Listed Submitted Date: November 12, 2014 Revision History Revision 1, 2014/10/04 - Initial version of this document Copyright Copyright (c) 2014 Aldo Facchin Leica GeoSystems(aldo . facchin @ leica-geosystems.com), All Rights Reserved. Permission is hereby granted, free of charge, to any person or organization obtaining a copy of this extension and accompanying documentation covered by this license (this "Extension") to use, reproduce, display, distribute, execute, and transmit this Extension, and to prepare derivative works of this Extension, and to permit third-parties to whom this Extension is furnished to do so, all subject to the following: The copyright notices in this Extension and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of this Extension, in whole or in part, and all derivative works of this Extension, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. Disclaimer THIS EXTENSION IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THIS EXTENSION BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THIS EXTENSION OR THE USE OR OTHER DEALINGS IN THIS EXTENSION.