Notifications
Clear all

[Closed] readDelimitedString if loop?

Hi all,

I’m a long-time but low complexity maxscripter, but I know what I want to do and generally I get there through recursive tinkering.
My main issue is usually knowing the appropriate terminology to search for.

Here is a snippet of the first few lines of a file (it’s an OS DTM format)

ncols 200
nrows 200
xllcorner 430000
yllcorner 250000
cellsize 50
68.6 69.2 69.6 70.2 71.2 71.9 73 74 75.3
89.2 88.2 80.3 79.4 86.7 87.8 85.9 81.5

Please note there are 200 lines of data, each with 200 entries per line in my actual file.

The area I’m struggling with is the readDelimitedString.


vert_array = #()
face_array = #()
	
 in_name = getOpenFileName()
 if in_name != undefined then
 (
  in_file = openFile in_name
  if in_file != undefined then
  (
	-- get ncols
	skipToString in_file "ncols"
	ncols = readLine in_file as integer
	
	-- get nrows
	skipToString in_file "nrows"
	nrows = readLine in_file as integer
	  
	-- get cellsize
	skipToString in_file "cellsize"
	cellsize = readLine in_file as integer
	
	num_verts = ncols * nrows
	--num_faces = (ncols - 1) * (nrows - 1) * 2
	  
	vert_array.count = num_verts
	--face_array.count = num_faces

	for r = 1 to nrows do
	(
		for v = 1 to ncols do
		(
			vert_y = readDelimitedString in_file " " as float
			vert_x = (v-1) * cellsize
			vert_z = (r-1) * cellsize
			
			x = vert_x as string
			y = vert_y as string
			z = vert_z as string

			xyz_array = execute ("[" + x + "," + y + "," + z + "]")

			
			index = (v)+(r)
			vert_array[index] = xyz_array
		)
		skipToNextLine in_file
	)
	
	close in_file
	--new_mesh = mesh vertices:vert_array
	  
	  -- debug
	debug= newScript()
	--print ncols to:debug
	--print nrows to:debug
	--print cellsize to:debug
	
	print vert_array to:debug
	print x to:debug
	print y to:debug
	print z to:debug
	
  )--end if
 )--end if

Right now this works ok, except that the last entry on every line ends in a carriage return, but I can’t seem to add a syntax that allows me to run an if or while statement referencing the ncols variable.

Basically I want to say something like this:


if v < ncols (
   read delimited string until " ")
else (
   read delimited string until "/r")

I’ve tried an if else statement, two if statements, and everything else I can think of but it’s breaking the code. Is there a certain way I should be doing this?

I’ve tried this which should work?


if v < ncols do (
function)
if v = ncols do (
other function)

Which I’m sure is the right maxscript syntax but it fails.

My quick bodge is find/replace on the data lines to add a trailing space before the carriage return… but I don’t like bodges.

Also note my horrible array filling using a string. I can’t seem to find any examples in the help files saying how to do this more elegantly.
I can’t seem to find anything saying how to use point3 arrays at all.

I’m also struggling recursing through the rows/columns and indexing the correct array entry to store the vert data, but I think that will be easier once I can just run through each point3 coord at a time, filling X then Y then Z.
I’ve not really got to that part yet though so if my code looks iffy please ignore haha!

Many thanks for any help

I’ll carry on working at it, I’m sure I’ll get there eventually…

Dave

7 Replies

everything looks ok in your code. just use readValue instead of readDelimitedString
about point3…
you already have x,y,z as floats. you don’t need them converted to string. the constructors for point3 are:


[x,y,z]
-- or
point3 x y z

where x,y,z are floats (or integers, which will be automatically converted to floats)

so in you case the code might look as:


if (file = getOpenFileName()) != undefined and (ss = openfile file) != undefined do
(
	vert_array = #()

	skipToString ss "ncols"
	ncols = readValue

	skipToString ss "nrows"
	nrows = readvalue ss

	skipToString ss "cellsize"
	cellsize = readValue ss

	num_verts = ncols * nrows
	vert_array.count = num_verts

	for r = 1 to nrows do
	(
		for v = 1 to ncols do
		(
			y = readValue ss
			x = (v-1) * cellsize
			z = (r-1) * cellsize

			vert_array[v+r] = [x,y,z]
		)
	)
	close ss
)

Hi DenisT,

Thanks for clarifying those things. Oh, I didn’t see the readValue method all the way down here haha. Never mind.

That all seems to work ok though. I’m getting some errors copying your code across but the syntax works ok.

I’m having trouble understanding why the v loop doesn’t complete first though.

This is my test file:


ncols 5
nrows 5
xllcorner 430000
yllcorner 250000
cellsize 50
1.1 1.2 1.3 1.4 1.5
1.6 1.7 1.8 1.9 2.0
2.1 2.2 2.3 2.4 2.5
2.6 2.7 2.8 2.9 3.0
3.1 3.2 3.3 3.4 3.5

And my output goes like this:


[0,1.1,0]
[0,1.6,50]
[0,2.1,100]
[0,2.6,150]
[0,3.1,200]
[50,3.2,200]
[100,3.3,200]
[150,3.4,200]
[200,3.5,200]
undefined
undefined
undefined
etc etc

I also had to put (r-1) in the array address so the array filled up from 1 > rather than 2 >

vert_array[v+(r-1)] = [x,y,z]

But it appears not to loop within the V loop fully 5 times (across the colums), and then exit the V loop with the readValue ready on the next line for the r=2 v=1 condition ready to read in the next line of values.

If I use readValue and get a raw stream of values it loops across then down fine in the first 5, then the next 5, then the next 5 values etc.

But it appears to be running through the r loop first!?

I’m probably missing something obvious. I’ll have to come back with a fresh brain tomorrow and see what happens.

Next task is then completing the face build, which should be a simple function once the vert array is working nicely!

Thanks

Dave

I think this is because of the way you’re calculating the index in vert_array to store the point3.

Give this (untested) a try.

vert_array[v + nrows * (r-1)] = [x,y,z]

Cheers,

Drea

Thanks Drea,

That appears to have done the trick.

I was looking at that but couldn’t see it, but now it makes sense. This is my problem with maxscripting, and coding in general. I use it but not enough to maintain solid skills…

Though I’ve decided to go through the video tutorials by JohnW to try fill in my blanks (lots of them) and have already found a few ways to optimise and imrpove this script!

Now to create some triangles!

If someone is willing to help make this script a bit more elegant once I’ve finished it it’d be nice to put it up on ScriptSpot. There are loads of GIS type 3D formats out there but precious few (none that are free) for getting things into 3DS Max or other ‘3D’ apps for more interesting visualisations.

Thanks

Dave

Well I started to get really confused with the function needed to draw triangles with the vertex indexes, but then also the function needed to put the triangles in the appropriate array index.

It got a little confused. I wasn’t far off filling in all the triangles for one set of verts, so was just going to do another pass to build the other triangle (and thus make a complete quad) with the array offset by the number of triangles in the first pass.

I’m sure there is an elegant way to do it but I just decided to cheat.

This is slower by a fair margin but it’s perfectly workable.


macroScript ImportMesh category: "OS OpenData Importers"
(
vert_array = #()
	
 in_name = getOpenFileName()
 if in_name != undefined then
 (
  in_file = openFile in_name
  if in_file != undefined then
  (
	-- get ncols
	skipToString in_file "ncols"
	ncols = readValue in_file
	
	-- get nrows
	skipToString in_file "nrows"
	nrows = readValue in_file
	  
	-- get cellsize
	skipToString in_file "cellsize"
	cellsize = readValue in_file
	
	num_verts = ncols * nrows
	  
	vert_array.count = num_verts
	

	-- put all the height data values into an array
	for v = 1 to num_verts do
	(
			z = readValue in_file
			vert_array[v] = z
	)
	
	close in_file

	
	
	-- create a plane (it appears I need to mirror the finished object in the y axis since the height data is actually addressed from the top left, despite the file reference coords being the bottom left!)
	-- this is slow, but it works, and maybe needs some manual mirroring at the end
	pwidth= ncols * cellsize
	plength = nrows * cellsize
	
	widthsegs = ncols-1
	lengthsegs = nrows-1
	
	convertToPoly(Plane length:plength width:pwidth pos:[pwidth/2,plength/2,0] isSelected:on lengthsegs:lengthsegs widthsegs:widthsegs name:"new_terrain")
	
	
	local theMesh = selection[1]

	if selection.count == 1 then
	(
		if classof theMesh == Editable_Poly then
		(
			n=1
			for vert in (theMesh.mesh.verts as bitarray) do
			(
				polyop.setVert theMesh vert [((polyop.getVert theMesh vert).x),((polyop.getVert theMesh vert).y),(((polyop.getVert theMesh vert).z) + vert_array[n])]
				n=n+1
				vert_array[1]
			)
		)
	)
  )
 )
)

I think this approach works pretty well, though it’s not optimal by any means.

This takes around 2min to process a 40k polygon DTM file, while my previous method was building a partially correct mesh in about 10s…

I’m quite surprised it’s so slow though. Is this because I’m looking up the existing xyz data per vert and then altering a specific z coord data with an offset?

I guess simply taking a vert z index only and setting it’s z value absolutely is going to be faster as it’s just pure writing, rather than reading values and then re-writing them all back (including x and y)

Cheers

Dave

Hmmm, maybe it’s not so workable.

It seems to use up a LOT of ram, and then leaves it resident once the mesh is built.

2GB > 16GB in about 30s, eek!

I can’t see what might be doing that… it’s a lot of memory…

Does the poly operation method do some caching? Maybe it’s caching the whole mesh each time it processes the next vert?!

Hmm

Dave