8
$\begingroup$

I'm trying to create a 3D heat map model out of data that I have from a csv file. I have a few thousand data points with XYZ coordinates.

I'm able to import the data into blender as a point cloud with this python script, however I would like to create a model with solid faces. Is there a way when importing the data to somehow join the points to create faces instead of generating thousands of separate points?

Currently, this what I have in terms of point cloudenter image description here

The end product would look something like this (minus the texture) and obviously the model wouldn't be as regular as this oneenter image description here

Any help is greatly appreciated!

$\endgroup$
  • 1
    $\begingroup$ Are the points in a regular order? Or may their index be semi-random? In the last case, you should probably obtain better results with Meshlab which has several tool for meshing pointclouds. $\endgroup$ – Carlo Mar 27 '17 at 22:21
  • $\begingroup$ Has said @Carlo, is there some constant aspects in the cloud of points? For instance in the file itself or because X,Y are a grid? To go further, could you give an access to a sample file? $\endgroup$ – lemon Mar 28 '17 at 11:42
  • $\begingroup$ The points are indexed randomly based on an arbitrary origin. I've uploaded a sample of the csv and a picture of what the data is representing. The X and Y coordinates are indeed a grid, while the Z value represent the power levels at that location. I've been able to mesh the point cloud in Meshlab with the Poisson reconstruction, however I'd ideally want to automate the model creation process in Blender only if possible. $\endgroup$ – DanielP Mar 28 '17 at 12:46
9
$\begingroup$

From the file you provided, here is the result:

enter image description here

Effectively, this is not as regular as the sample image in the question!!

This script works only if we have a rectangular grid along X and Y.

Here is commented code (tell me if some additional explanations are needed):

import bpy
import csv
from operator import itemgetter

csvfile = open('G:\\Telechargements\\Heatmap_ES_output_01.csv')

inFile = csv.reader(csvfile, delimiter=',', quotechar='"')
# skip header
inFile.__next__()

#Read and sort the vertices coordinates (sort by x and y)
vertices = sorted( [(float(r[0]), float(r[1]), float(r[2])) for r in inFile], key = itemgetter(0,1) )

#********* Assuming we have a rectangular grid *************
xSize = next( i for i in range( len(vertices) ) if vertices[i][0] != vertices[i+1][0] ) + 1 #Find the first change in X
ySize = len(vertices) // xSize

#Generate the polygons (four vertices linked in a face)
polygons = [(i, i - 1, i - 1 + xSize, i + xSize) for i in range( 1, len(vertices) - xSize ) if i % xSize != 0]

name = "grid"
mesh = bpy.data.meshes.new( name ) #Create the mesh (inner data)
obj = bpy.data.objects.new( name, mesh ) #Create an object

obj.data.from_pydata( vertices, [], polygons ) #Associate vertices and polygons

obj.scale = (1, 5, 0.2) #Scale it (if needed)
for p in obj.data.polygons: #Set smooth shading (if needed)
    p.use_smooth = True

bpy.context.scene.objects.link( obj ) #Link the object to the scene

Blender 2.8

For 2.8:

The last line:

bpy.context.scene.objects.link( obj )

should be replaced by:

bpy.context.scene.collection.objects.link( obj )
| improve this answer | |
$\endgroup$
  • $\begingroup$ This works perfectly for the data that I have. If you don't mind, could you explain the line 'polygons = [(i, i - 1, i - 1 + xSize, i + xSize) for i in range( 1, len(vertices) - xSize ) if i % xSize != 0]' ? I get that it creates the face between 4 vertices, but I don't understand the 'if' statement at the end. Merci! $\endgroup$ – DanielP Mar 28 '17 at 17:17
  • $\begingroup$ i modulo the width. That allows to skip 0, 1*width, 2*width, ... as vertex index. Between 3 points you have 2 faces (edges). Je ne sais pas si je suis clair... !! $\endgroup$ – lemon Mar 28 '17 at 17:27
6
$\begingroup$

Here's a possible solution using Sverchok add-on:

Basically we can import the ponts directy from the cvs file with the Text input node and tranform the coordinates in vertices with the Vector in node.

Then what's left is to provide a sequence of indexes based on the specific grid of acquisition. In this particular case, we are defining the first polygon (a quad) an then repeating the process for every quadrlet with a combination of list managing and a int range.

enter image description here

The last segment of the algorithm is used to get rid of the faces built by the vertices of a row and the first of another. In this particular case is deleting one item of the list every 216.

| improve this answer | |
$\endgroup$
  • $\begingroup$ Interesting (+1). About your note, this is precisely the question of the OP in the comment (the need of i%xSize). Is there a way to do it with Sverchock? $\endgroup$ – lemon Mar 28 '17 at 17:51
  • 2
    $\begingroup$ Yes, you can implement the same math you used, or use methods like the one I added to the answer. $\endgroup$ – Carlo Mar 28 '17 at 18:25
  • $\begingroup$ I tried to plot using your script. It is showing error can you have quick look CSV file is here drive.google.com/open?id=1VRqSRnDcolSaYv-_6UsfdKV8uaov3Z41 $\endgroup$ – Rafeeque Bin Usman Feb 23 at 23:13
  • $\begingroup$ Unfortunately the script works only for a rectangular grid distribution of points like the one provided by the OP. Yours needs a different implementation, like a marching cube alghorithm or something similar. There is no trivial solution. $\endgroup$ – Carlo Feb 27 at 18:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.