I have just started exploring QGIS to display point cloud data.
I have written a python script in QGIS which fetches point data from a backend service and creates layer with it.
class FetchPointsAlgorithm(QgsProcessingAlgorithm):
ENDPOINT = 'ENDPOINT'
OUTPUT = 'OUTPUT'
def initAlgorithm(self, config=None):
"""
Define the parameters and outputs of the algorithm.
"""
self.addParameter(
QgsProcessingParameterString(
self.ENDPOINT,
'REST Endpoint URL',
defaultValue='....'
)
)
self.addParameter(
QgsProcessingParameterFeatureSink(
self.OUTPUT,
'Output Layer'
)
)
def processAlgorithm(self, parameters, context, feedback):
url = self.parameterAsString(parameters, self.ENDPOINT, context)
# Create an empty vector layer
layer, provider = self.createLayer(context)
try:
# Fetch data from the REST endpoint
response = requests.get(url, stream=True)
response.raise_for_status()
all_data = []
chunks = response.iter_content(chunk_size=None, decode_unicode=True)
buffer = ""
count = 0
# Use next to fetch one chunk at a time
try:
while True:
chunk = next(chunks)
if chunk:
buffer += chunk # Append chunk to buffer
try:
# Try to parse the buffer as JSON
json_list = json.loads(buffer)
buffer = "" # Clear buffer after successful parsing
features = []
count += len(json_list)
for record in json_list:
#print(record)
if all(key in record for key in ('x', 'y', 'z', 'red', 'green', 'blue')):
point = QgsPoint(record['x'], record['y'], record['z'])
feat = QgsFeature()
feat.setGeometry(QgsGeometry.fromPoint(point))
feat.setAttributes([
record['x'],
record['y'],
record['z'],
record['red'],
record['green'],
record['blue']
])
features.append(feat)
if features:
provider.addFeatures(features)
print("Total points so far:"+str(count))
layer.updateExtents()
QgsProject.instance().addMapLayer(layer)
except json.JSONDecodeError:
# continue accumulating chunks
continue
except StopIteration:
print(".....")
except requests.RequestException as e:
feedback.reportError(f"Error fetching data: {e}")
except json.JSONDecodeError as e:
feedback.reportError(f"Error decoding JSON: {e}")
return {self.OUTPUT: layer}
def createLayer(self, context):
layer = QgsVectorLayer('Point?crs=EPSG:26916', 'MyLayer', 'memory')
provider = layer.dataProvider()
provider.addAttributes([
QgsField('x', QVariant.Double),
QgsField('y', QVariant.Double),
QgsField('z', QVariant.Double),
QgsField('red', QVariant.Int),
QgsField('green', QVariant.Int),
QgsField('blue', QVariant.Int)
])
layer.updateFields()
return layer, provider
def name(self):
"""
Returns the algorithm name.
"""
return 'fetch_points'
def displayName(self):
"""
Returns the display name for the algorithm.
"""
return 'Fetch Points from REST Endpoint'
def group(self):
"""
Returns the group name for the algorithm.
"""
return 'Custom Algorithms'
def groupId(self):
"""
Returns the group ID for the algorithm.
"""
return 'custom_algorithms'
def createInstance(self):
"""
Returns a new instance of the algorithm.
"""
return FetchPointsAlgorithm()
Most of the work is done in createLayer and processAlgorithm.
createLayer defines structure of the layer.
processAlgorithm fetches the point data in chunks(stream=true), extracts points from it, create QgsPoint from x,y,z values for every point and add it to QgsFeature, and then calls setAttributes on that feature.
I expect a 3D point distribution as I have used QgsPoint to set feature geometry, but instead I see 2D.
Seems my understanding of QGIS scripting and layers is not correct.
What mistake am I making in my code?