1 /***************************************************************************
2 qgsmultipoint.cpp
3 -------------------------------------------------------------------
4 Date : 29 Oct 2014
5 Copyright : (C) 2014 by Marco Hugentobler
6 email : marco.hugentobler at sourcepole dot com
7 ***************************************************************************
8 * *
9 * This program is free software; you can redistribute it and/or modify *
10 * it under the terms of the GNU General Public License as published by *
11 * the Free Software Foundation; either version 2 of the License, or *
12 * (at your option) any later version. *
13 * *
14 ***************************************************************************/
15
16 #include "qgsmultipoint.h"
17 #include "qgsapplication.h"
18 #include "qgsgeometryutils.h"
19 #include "qgspoint.h"
20 #include "qgswkbptr.h"
21
22 #include <QJsonArray>
23 #include <QJsonObject>
24 #include <QRegularExpression>
25 #include <nlohmann/json.hpp>
26
QgsMultiPoint()27 QgsMultiPoint::QgsMultiPoint()
28 {
29 mWkbType = QgsWkbTypes::MultiPoint;
30 }
31
pointN(int index)32 QgsPoint *QgsMultiPoint::pointN( int index )
33 {
34 return qgsgeometry_cast< QgsPoint * >( geometryN( index ) );
35 }
36
pointN(int index) const37 const QgsPoint *QgsMultiPoint::pointN( int index ) const
38 {
39 return qgsgeometry_cast< const QgsPoint * >( geometryN( index ) );
40 }
41
geometryType() const42 QString QgsMultiPoint::geometryType() const
43 {
44 return QStringLiteral( "MultiPoint" );
45 }
46
createEmptyWithSameType() const47 QgsMultiPoint *QgsMultiPoint::createEmptyWithSameType() const
48 {
49 auto result = std::make_unique< QgsMultiPoint >();
50 result->mWkbType = mWkbType;
51 return result.release();
52 }
53
clone() const54 QgsMultiPoint *QgsMultiPoint::clone() const
55 {
56 return new QgsMultiPoint( *this );
57 }
58
toCurveType() const59 QgsMultiPoint *QgsMultiPoint::toCurveType() const
60 {
61 return clone();
62 }
63
fromWkt(const QString & wkt)64 bool QgsMultiPoint::fromWkt( const QString &wkt )
65 {
66 QString collectionWkt( wkt );
67 //test for non-standard MultiPoint(x1 y1, x2 y2) format
68 const thread_local QRegularExpression regex( QStringLiteral( "^\\s*MultiPoint\\s*[ZM]*\\s*\\(\\s*[-\\d]" ), QRegularExpression::CaseInsensitiveOption );
69 const QRegularExpressionMatch match = regex.match( collectionWkt );
70 if ( match.hasMatch() )
71 {
72 //alternate style without extra brackets, upgrade to standard
73 collectionWkt.replace( '(', QLatin1String( "((" ) ).replace( ')', QLatin1String( "))" ) ).replace( ',', QLatin1String( "),(" ) );
74 }
75
76 return fromCollectionWkt( collectionWkt, QVector<QgsAbstractGeometry *>() << new QgsPoint, QStringLiteral( "Point" ) );
77 }
78
clear()79 void QgsMultiPoint::clear()
80 {
81 QgsGeometryCollection::clear();
82 mWkbType = QgsWkbTypes::MultiPoint;
83 }
84
asGml2(QDomDocument & doc,int precision,const QString & ns,const AxisOrder axisOrder) const85 QDomElement QgsMultiPoint::asGml2( QDomDocument &doc, int precision, const QString &ns, const AxisOrder axisOrder ) const
86 {
87 QDomElement elemMultiPoint = doc.createElementNS( ns, QStringLiteral( "MultiPoint" ) );
88
89 if ( isEmpty() )
90 return elemMultiPoint;
91
92 for ( const QgsAbstractGeometry *geom : mGeometries )
93 {
94 if ( qgsgeometry_cast<const QgsPoint *>( geom ) )
95 {
96 QDomElement elemPointMember = doc.createElementNS( ns, QStringLiteral( "pointMember" ) );
97 elemPointMember.appendChild( geom->asGml2( doc, precision, ns, axisOrder ) );
98 elemMultiPoint.appendChild( elemPointMember );
99 }
100 }
101
102 return elemMultiPoint;
103 }
104
asGml3(QDomDocument & doc,int precision,const QString & ns,const QgsAbstractGeometry::AxisOrder axisOrder) const105 QDomElement QgsMultiPoint::asGml3( QDomDocument &doc, int precision, const QString &ns, const QgsAbstractGeometry::AxisOrder axisOrder ) const
106 {
107 QDomElement elemMultiPoint = doc.createElementNS( ns, QStringLiteral( "MultiPoint" ) );
108
109 if ( isEmpty() )
110 return elemMultiPoint;
111
112 for ( const QgsAbstractGeometry *geom : mGeometries )
113 {
114 if ( qgsgeometry_cast<const QgsPoint *>( geom ) )
115 {
116 QDomElement elemPointMember = doc.createElementNS( ns, QStringLiteral( "pointMember" ) );
117 elemPointMember.appendChild( geom->asGml3( doc, precision, ns, axisOrder ) );
118 elemMultiPoint.appendChild( elemPointMember );
119 }
120 }
121
122 return elemMultiPoint;
123 }
124
asJsonObject(int precision) const125 json QgsMultiPoint::asJsonObject( int precision ) const
126 {
127 json j
128 {
129 { "type", "MultiPoint" },
130 { "coordinates", json::array() },
131 };
132 for ( const QgsAbstractGeometry *geom : std::as_const( mGeometries ) )
133 {
134 const QgsPoint *point = static_cast<const QgsPoint *>( geom );
135 if ( point->is3D() )
136 j[ "coordinates" ].push_back( { qgsRound( point->x(), precision ), qgsRound( point->y(), precision ), qgsRound( point->z(), precision ) } );
137 else
138 j[ "coordinates" ].push_back( { qgsRound( point->x(), precision ), qgsRound( point->y(), precision ) } );
139 }
140 return j;
141 }
142
143
nCoordinates() const144 int QgsMultiPoint::nCoordinates() const
145 {
146 return mGeometries.size();
147 }
148
addGeometry(QgsAbstractGeometry * g)149 bool QgsMultiPoint::addGeometry( QgsAbstractGeometry *g )
150 {
151 if ( !qgsgeometry_cast<QgsPoint *>( g ) )
152 {
153 delete g;
154 return false;
155 }
156 if ( mGeometries.empty() )
157 {
158 setZMTypeFromSubGeometry( g, QgsWkbTypes::MultiPoint );
159 }
160 if ( is3D() && !g->is3D() )
161 g->addZValue();
162 else if ( !is3D() && g->is3D() )
163 g->dropZValue();
164 if ( isMeasure() && !g->isMeasure() )
165 g->addMValue();
166 else if ( !isMeasure() && g->isMeasure() )
167 g->dropMValue();
168
169 return QgsGeometryCollection::addGeometry( g );
170 }
171
insertGeometry(QgsAbstractGeometry * g,int index)172 bool QgsMultiPoint::insertGeometry( QgsAbstractGeometry *g, int index )
173 {
174 if ( !g || QgsWkbTypes::flatType( g->wkbType() ) != QgsWkbTypes::Point )
175 {
176 delete g;
177 return false;
178 }
179
180 return QgsGeometryCollection::insertGeometry( g, index );
181 }
182
boundary() const183 QgsAbstractGeometry *QgsMultiPoint::boundary() const
184 {
185 return nullptr;
186 }
187
vertexNumberFromVertexId(QgsVertexId id) const188 int QgsMultiPoint::vertexNumberFromVertexId( QgsVertexId id ) const
189 {
190 if ( id.part < 0 || id.part >= mGeometries.count() || id.vertex != 0 || id.ring != 0 )
191 return -1;
192
193 return id.part; // can shortcut the calculation, since each part will have 1 vertex
194 }
195
segmentLength(QgsVertexId) const196 double QgsMultiPoint::segmentLength( QgsVertexId ) const
197 {
198 return 0.0;
199 }
200
isValid(QString &,Qgis::GeometryValidityFlags) const201 bool QgsMultiPoint::isValid( QString &, Qgis::GeometryValidityFlags ) const
202 {
203 return true;
204 }
205
filterVertices(const std::function<bool (const QgsPoint &)> & filter)206 void QgsMultiPoint::filterVertices( const std::function<bool ( const QgsPoint & )> &filter )
207 {
208 mGeometries.erase( std::remove_if( mGeometries.begin(), mGeometries.end(), // clazy:exclude=detaching-member
209 [&filter]( const QgsAbstractGeometry * part )
210 {
211 if ( const QgsPoint *point = qgsgeometry_cast< const QgsPoint * >( part ) )
212 {
213 if ( !filter( *point ) )
214 {
215 delete point;
216 return true;
217 }
218 else
219 {
220 return false;
221 }
222 }
223 else
224 {
225 delete part;
226 return true;
227 }
228 } ), mGeometries.end() ); // clazy:exclude=detaching-member
229 }
230
wktOmitChildType() const231 bool QgsMultiPoint::wktOmitChildType() const
232 {
233 return true;
234 }
235