martedì 13 aprile 2010

Creating a 3D terrain from height measurements

Sometimes we architects have to create a digital representation of a ground surface topography (DEM) for 3D visualizations. I usually start with a .dwg file and a bunch of  height measurements. The image on the left is a typical case.
I invented an "original" way to crank out a digital elevation model.
I usually use AutoCAD Map and a couple of extra tools.
I export all measurements in a text file and then import it into AutoCAD Map. Exporting all measurements is quite simple: I use CAD2FILE, a free Lisp program that allows me to export all needed parameters into a text file.

We can select the file type to create (on the left) and the properties to send to the file. In my case I select Insertion Point and click  Okay.

The result is a text file with this structure:

Start X,Start Y,Start Z,Text Value,
2318050.04,4644289.52,0,12.4,
2318382.41,4643741.07,0,12.4,
2318385,4643737.46,0,12.4,
2318387.03,4643734.37,0,12.4,
...

Start X, Start Y,Start Z are the coordinates of the insertion point of the measurement. Value is the measurement.

Cool! What I wanna do now is fix this file because AutoCAD Map can import a series of x, y and z coordinates only, without other parameters.
To do this I wrote a simple Java program named Virgola:




// Author: Stefano Bolli
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import java.io.*;

public class Virgola {

public static void main(String[] args) {
Virgola virgola = new Virgola();
}

public Virgola() {

// Text directory
File textDir = new File(".");
// Filter for text files
TextFilter tfilter = new TextFilter();
// Text files
String[] textList = textDir.list(tfilter);

if (textList.length == 1 ) {
System.out.println("I found the file:" + "\n");
System.out.println(textList[0] + "\n");
System.out.println("I'm fixing the file...");
readFile(textList[0]);
}
else if (textList.length > 0) {
System.out.println("\nFound multiple files. Indicate the file you wanna fix:");
System.out.println("\n");

for (int i = 0; i < textList.length; i++)
System.out.println(i + ") " + textList[i]);
try {
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
String fileChoosen = in.readLine();
int x = Integer.parseInt(fileChoosen);
readFile(textList[x]);
} catch (IOException e) { }
}
else
System.out.println("No text file found");
}

public void readFile(String fileToRead) {
try {
BufferedReader br = new BufferedReader(new FileReader(new File(fileToRead)));
String line;
Vector vector = new Vector();
while ((line = br.readLine()) != null) {
// Store the row in the vector.
vector.addElement(line);
}
br.close();
SaveFile(vector, changeNameToFile(fileToRead));
}
catch (IOException e) { } }
public String changeNameToFile(String name) {
String newName = name.substring(0, name.lastIndexOf(".")) + "_fixed_by_Virgola.txt";
return newName;
}
public void SaveFile(Vector v, String fileToSave) {
try {
BufferedWriter out = new BufferedWriter(new FileWriter(fileToSave));
for (int i = 0; i < v.size(); i++) {
String s = (String)v.elementAt(i);
if (!s.startsWith("Start")) {
out.write(cleanLine(s) + "\n");
}
}
out.flush();
out.close();
} catch (IOException e) {
}
}
public String cleanLine(String line) {
String oldLine = line.substring(0, line.lastIndexOf(","));
String newLine = oldLine.substring(0, oldLine.indexOf(",0,")) + oldLine.substring(oldLine.lastIndexOf(","));
return newLine;
}
/** * Filter for text files. */
class TextFilter implements FilenameFilter {
public boolean accept(File dir, String name) {
boolean acceptFile = false;
if (name.endsWith(".txt"))
acceptFile = true;
return acceptFile;
}
}
}


If someone needs this program, I can compile it and send as .exe file.


Ok, now we can import the text file into AutoCAD Map and create the terrain.
The final mesh is a triangular irregular network and can be imported into 3d softwares like Maya o 3DS Max: as you can see, I was working on a level land with a river. There are a few errors I can fix quickly before smoothing the mesh.

Best regards.