1 /***************************************************************************
2                          qgspointcloudattribute.cpp
3                          -----------------------
4     begin                : October 2020
5     copyright            : (C) 2020 by Peter Petrik
6     email                : zilolv at gmail dot com
7  ***************************************************************************/
8 
9 /***************************************************************************
10  *                                                                         *
11  *   This program is free software; you can redistribute it and/or modify  *
12  *   it under the terms of the GNU General Public License as published by  *
13  *   the Free Software Foundation; either version 2 of the License, or     *
14  *   (at your option) any later version.                                   *
15  *                                                                         *
16  ***************************************************************************/
17 
18 #include "qgis.h"
19 #include "qgspointcloudattribute.h"
20 
21 QgsPointCloudAttribute::QgsPointCloudAttribute() = default;
22 
QgsPointCloudAttribute(const QString & name,DataType type)23 QgsPointCloudAttribute::QgsPointCloudAttribute( const QString &name, DataType type )
24   : mName( name )
25   , mType( type )
26 {
27   updateSize();
28 }
29 
variantType() const30 QVariant::Type QgsPointCloudAttribute::variantType() const
31 {
32   switch ( mType )
33   {
34     case DataType::Char:
35     case DataType::Short:
36     case DataType::UShort:
37     case DataType::Int32:
38       return QVariant::Int;
39 
40     case DataType::Float:
41     case DataType::Double:
42       return QVariant::Double;
43   }
44   return QVariant::Invalid;
45 }
46 
displayType() const47 QString QgsPointCloudAttribute::displayType() const
48 {
49   switch ( mType )
50   {
51     case DataType::Char:
52       return QObject::tr( "Character" );
53     case DataType::Short:
54       return QObject::tr( "Short" );
55     case DataType::UShort:
56       return QObject::tr( "Unsigned Short" );
57     case DataType::Float:
58       return QObject::tr( "Float" );
59     case DataType::Int32:
60       return QObject::tr( "Integer" );
61     case DataType::Double:
62       return QObject::tr( "Double" );
63   }
64   return QString();
65 }
66 
isNumeric(QgsPointCloudAttribute::DataType type)67 bool QgsPointCloudAttribute::isNumeric( QgsPointCloudAttribute::DataType type )
68 {
69   switch ( type )
70   {
71     case DataType::Char:
72       return false;
73     case DataType::Short:
74     case DataType::UShort:
75     case DataType::Float:
76     case DataType::Int32:
77     case DataType::Double:
78       return true;
79   }
80   return false;
81 }
82 
updateSize()83 void QgsPointCloudAttribute::updateSize()
84 {
85   switch ( mType )
86   {
87     case DataType::Char:
88       mSize = 1;
89       break;
90     case DataType::Short:
91     case DataType::UShort:
92       mSize = 2;
93       break;
94     case DataType::Float:
95       mSize = 4;
96       break;
97     case DataType::Int32:
98       mSize = 4;
99       break;
100     case DataType::Double:
101       mSize = 8;
102       break;
103   }
104 }
105 
106 // //////////////////
107 
108 QgsPointCloudAttributeCollection::QgsPointCloudAttributeCollection() = default;
109 
QgsPointCloudAttributeCollection(const QVector<QgsPointCloudAttribute> & attributes)110 QgsPointCloudAttributeCollection::QgsPointCloudAttributeCollection( const QVector<QgsPointCloudAttribute> &attributes )
111 {
112   mAttributes.reserve( attributes.size() );
113   for ( const QgsPointCloudAttribute &attribute : attributes )
114   {
115     push_back( attribute );
116   }
117 }
118 
push_back(const QgsPointCloudAttribute & attribute)119 void QgsPointCloudAttributeCollection::push_back( const QgsPointCloudAttribute &attribute )
120 {
121   mCachedAttributes.insert( attribute.name(), CachedAttributeData( mAttributes.size(), mSize ) );
122   mAttributes.push_back( attribute );
123   mSize += attribute.size();
124 }
125 
attributes() const126 QVector<QgsPointCloudAttribute> QgsPointCloudAttributeCollection::attributes() const
127 {
128   return mAttributes;
129 }
130 
find(const QString & attributeName,int & offset) const131 const QgsPointCloudAttribute *QgsPointCloudAttributeCollection::find( const QString &attributeName, int &offset ) const
132 {
133   const auto it = mCachedAttributes.constFind( attributeName );
134   if ( it != mCachedAttributes.constEnd() )
135   {
136     offset = it->offset;
137     return &mAttributes.at( it->index );
138   }
139 
140   // not found
141   return nullptr;
142 }
143 
indexOf(const QString & name) const144 int QgsPointCloudAttributeCollection::indexOf( const QString &name ) const
145 {
146   const auto it = mCachedAttributes.constFind( name );
147   if ( it != mCachedAttributes.constEnd() )
148   {
149     return it->index;
150   }
151 
152   // not found
153   return -1;
154 }
155 
toFields() const156 QgsFields QgsPointCloudAttributeCollection::toFields() const
157 {
158   QgsFields fields;
159   for ( const QgsPointCloudAttribute &attribute : mAttributes )
160   {
161     fields.append( QgsField( attribute.name(), attribute.variantType(), attribute.displayType() ) );
162   }
163   return fields;
164 }
165 
166 template <typename T>
_attribute(const char * data,std::size_t offset,QgsPointCloudAttribute::DataType type,T & value)167 void _attribute( const char *data, std::size_t offset, QgsPointCloudAttribute::DataType type, T &value )
168 {
169   switch ( type )
170   {
171     case QgsPointCloudAttribute::Char:
172       value = *( data + offset );
173       break;
174 
175     case QgsPointCloudAttribute::Int32:
176       value = *reinterpret_cast< const qint32 * >( data + offset );
177       break;
178 
179     case QgsPointCloudAttribute::Short:
180     {
181       value = *reinterpret_cast< const short * >( data + offset );
182     }
183     break;
184 
185     case QgsPointCloudAttribute::UShort:
186       value = *reinterpret_cast< const unsigned short * >( data + offset );
187       break;
188 
189     case QgsPointCloudAttribute::Float:
190       value = static_cast< T >( *reinterpret_cast< const float * >( data + offset ) );
191       break;
192 
193     case QgsPointCloudAttribute::Double:
194       value = *reinterpret_cast< const double * >( data + offset );
195       break;
196   }
197 }
198 
getPointXYZ(const char * ptr,int i,std::size_t pointRecordSize,int xOffset,QgsPointCloudAttribute::DataType xType,int yOffset,QgsPointCloudAttribute::DataType yType,int zOffset,QgsPointCloudAttribute::DataType zType,const QgsVector3D & indexScale,const QgsVector3D & indexOffset,double & x,double & y,double & z)199 void QgsPointCloudAttribute::getPointXYZ( const char *ptr, int i, std::size_t pointRecordSize, int xOffset, QgsPointCloudAttribute::DataType xType,
200     int yOffset, QgsPointCloudAttribute::DataType yType,
201     int zOffset, QgsPointCloudAttribute::DataType zType,
202     const QgsVector3D &indexScale, const QgsVector3D &indexOffset, double &x, double &y, double &z )
203 {
204   _attribute( ptr, i * pointRecordSize + xOffset, xType, x );
205   x = indexOffset.x() + indexScale.x() * x;
206 
207   _attribute( ptr, i * pointRecordSize + yOffset, yType, y );
208   y = indexOffset.y() + indexScale.y() * y;
209 
210   _attribute( ptr, i * pointRecordSize + zOffset, zType, z );
211   z = indexOffset.z() + indexScale.z() * z;
212 }
213 
getAttributeMap(const char * data,std::size_t recordOffset,const QgsPointCloudAttributeCollection & attributeCollection)214 QVariantMap QgsPointCloudAttribute::getAttributeMap( const char *data, std::size_t recordOffset, const QgsPointCloudAttributeCollection &attributeCollection )
215 {
216   QVariantMap map;
217   const QVector<QgsPointCloudAttribute> attributes = attributeCollection.attributes();
218   for ( const QgsPointCloudAttribute &attr : attributes )
219   {
220     const QString attributeName = attr.name();
221     int attributeOffset;
222     attributeCollection.find( attributeName, attributeOffset );
223     switch ( attr.type() )
224     {
225       case QgsPointCloudAttribute::Char:
226       {
227         const char value = *( data + recordOffset + attributeOffset );
228         map[ attributeName ] = value;
229       }
230       break;
231 
232       case QgsPointCloudAttribute::Int32:
233       {
234         const qint32 value = *reinterpret_cast< const qint32 * >( data + recordOffset + attributeOffset );
235         map[ attributeName ] = value;
236       }
237       break;
238 
239       case QgsPointCloudAttribute::Short:
240       {
241         const short value = *reinterpret_cast< const short * >( data + recordOffset + attributeOffset );
242         map[ attributeName ] = value;
243       }
244       break;
245 
246       case QgsPointCloudAttribute::UShort:
247       {
248         const unsigned short value = *reinterpret_cast< const unsigned short * >( data + recordOffset + attributeOffset );
249         map[ attributeName ] = value;
250       }
251       break;
252 
253       case QgsPointCloudAttribute::Float:
254       {
255         const float value = *reinterpret_cast< const float * >( data + recordOffset + attributeOffset );
256         map[ attributeName ] = value;
257       }
258       break;
259 
260       case QgsPointCloudAttribute::Double:
261       {
262         const double value = *reinterpret_cast< const double * >( data + recordOffset + attributeOffset );
263         map[ attributeName ] = value;
264       }
265       break;
266     }
267   }
268   return map;
269 }
270