Hey Chris, I quickly (read - some things may not work!) refactored my old
.PLY importer for you. should work...
Just rename as .py and run in the script editor.
Like Alan suggested though, it's just point data so it just makes a
pointcloud.
Hope it helps.
DAN
On Mon, Jan 7, 2013 at 5:09 PM, Chris Marshall <[email protected]>wrote:
> Hi,
> Sorry for the slow reply on this. We have an xyz file, which is just a
> grid of points, like this:-
>
> -105.2500000000,39.7500000000,1757.129
> -105.2500000000,39.7499583333,1758.791
> -105.2500000000,39.7499166667,1760.882
> -105.2500000000,39.7498750000,1763.025
> -105.2500000000,39.7498333333,1765.183
> -105.2500000000,39.7497916667,1767.467
> -105.2500000000,39.7497500000,1768.741
> -105.2500000000,39.7497083333,1771.766
> -105.2500000000,39.7496666667,1773.832
> -105.2500000000,39.7496250000,1775.873
> -105.2500000000,39.7495833333,1777.84
> -105.2500000000,39.7495416667,1779.369
> -105.2500000000,39.7495000000,1781.255
> -105.2500000000,39.7494583333,1783.423
> -105.2500000000,39.7494166667,1785.815
> -105.2500000000,39.7493750000,1788.552
> -105.2500000000,39.7493333333,1791.749
> -105.2500000000,39.7492916667,1795.332
> -105.2500000000,39.7492500000,1800.269
> -105.2500000000,39.7492083333,1804.516
> -105.2500000000,39.7491666667,1808.3
>
> So it must be relatively easy to convert this into a grid? Anyone got any
> ideas or can supply a simple script we can modify that'll read this data
> and generate a new grid or adjust the height of an existing grid?
>
> Thanks
>
> Chris
>
>
>
>
> On 14 December 2012 19:12, Matt Lind <[email protected]> wrote:
>
>> If it’s ASCII, an importer can probably be written fairly easily.****
>>
>> ** **
>>
>> Do you have a sample file?****
>>
>> ** **
>>
>> ** **
>>
>> Matt****
>>
>> ** **
>>
>> ** **
>>
>> ** **
>>
>> *From:* [email protected] [mailto:
>> [email protected]] *On Behalf Of *Chris Marshall
>> *Sent:* Friday, December 14, 2012 5:19 AM
>> *To:* [email protected]
>> *Subject:* terrain ascii xyz import****
>>
>> ** **
>>
>> Hello,****
>>
>> Anyone know how to get these into soft?****
>>
>> ** **
>>
>> Cheers****
>>
>> ** **
>>
>> Chris****
>>
>> ** **
>>
>
>
>
> --
>
> Chris Marshall
> Mint Motion Limited
> 029 20 37 27 57
> 07730 533 115
> www.mintmotion.co.uk
>
>
import sys
import random
import gzip
import os
import re
from struct import pack
import win32com.client
from win32com.client import constants
## Globals
null = None
false = 0
true = 1
xsi = Application
pr = xsi.LogMessage
def main():
# Browse for the .XYZ file
xyzFilePath = GetXYZfilePath()
if xyzFilePath:
# Retreive the point data from the .XYZ file
pointsList = GetPointsList(xyzFilePath)
nbPoints = len(pointsList)
if nbPoints > 0:
# Get user input
oPset = GetInputValues(nbPoints)
if oPset:
pointsPerc = oPset.pPointsPerc.value
# Take the list of point data and rework it for
softimage - Use user input to filter/modify the data.
pointDataList = ParsePoints(pointsList,
pointsPerc)
nbPoints = len(pointDataList)
# Write the icecache
cachePath = WriteIceCache(xyzFilePath,
pointDataList, oPset.pPointSize.value)
# Create an empty pointcloud under a model
cloudModel =
xsi.ActiveSceneRoot.AddModel("",xyzfileName + "_model")
pointCloud =
cloudModel.AddPrimitive("pointcloud", xyzfileName)
# Load in out newly created icecache
xsi.AddFileCacheSource(pointCloud, cachePath)
# Cleanup...
xsi.FreezeObj(pointCloud)
xsi.DeleteObj(cloudModel.Fullname + ".Mixer")
# I figure one more command isn't gonna hurt
after the 3 above this... ;)
xsi.SetValue(pointCloud.Fullname +
".particledisplay.displaytype", 1, "")
else:
pr("Aborting!!!")
xsi.DeleteObj(oPset)
else:
pr("Error - no points found or not a valid XYZ file!!!")
else:
pr("Error - no XYZ file!!!")
return
def GetInputValues(nbPoints):
# Setup the Custom Pset and inspect Modally - Define the Pset as a
global
global oPset
oPset = xsi.ActiveSceneRoot.AddCustomProperty("XYZ_ImportOptions")
pImportPerc = oPset.AddParameter2("pPointsPerc", constants.siInt2, 100,
0, 100, 0, 100)
pSpatialScale = oPset.AddParameter2("pSpatialScale", constants.siFloat,
1, 0, 1000, 0, 1)
pNullScale = oPset.AddParameter2("pPointSize", constants.siFloat, 0.1,
0, 1000, 0, 1)
pBoundsFilter = oPset.AddParameter2("pFilterByBounds",
constants.siBool, 0, 0, 1, 0, 1)
pBoundMinX = oPset.AddParameter2("pBoundMinX", constants.siFloat,
-1000, -1000, 1000, -1000, 1000)
pBoundMinY = oPset.AddParameter2("pBoundMinY", constants.siFloat,
-1000, -1000, 1000, -1000, 1000)
pBoundMinZ = oPset.AddParameter2("pBoundMinZ", constants.siFloat,
-1000, -1000, 1000, -1000, 1000)
pBoundMaxX = oPset.AddParameter2("pBoundMaxX", constants.siFloat, 1000,
-1000, 1000, -1000, 1000)
pBoundMaxY = oPset.AddParameter2("pBoundMaxY", constants.siFloat, 1000,
-1000, 1000, -1000, 1000)
pBoundMaxZ = oPset.AddParameter2("pBoundMaxZ", constants.siFloat, 1000,
-1000, 1000, -1000, 1000)
oLayout = oPset.PPGLayout
oLayout.Clear()
oLayout.AddGroup("Import Options")
oLayout.AddStaticText( "\n" + str(nbPoints) + " Points were found in
.XYZ file '" + xyzfileName + "'\n" )
iImportPerc = oLayout.AddItem("pPointsPerc", "Approximate Percentage of
Points to Import", constants.siControlNumber )
iImportPerc.LabelMinPixels = 160
oLayout.EndGroup()
oLayout.AddGroup("Scaling Options")
oLayout.AddItem("pSpatialScale", "Scale Dataset",
constants.siControlNumber )
oLayout.AddItem("pPointSize", "Size of Points",
constants.siControlNumber )
oLayout.EndGroup()
oLayout.AddGroup("Pointcloud Bounds")
oLayout.AddItem("pFilterByBounds", "Filter points by bounding volume",
constants.siControlBoolean )
oLayout.AddRow()
oLayout.AddItem("pBoundMinX", "Min X", constants.siControlNumber )
oLayout.AddItem("pBoundMaxX", "Max X", constants.siControlNumber )
oLayout.EndRow()
oLayout.AddRow()
oLayout.AddItem("pBoundMinY", "Min Y", constants.siControlNumber )
oLayout.AddItem("pBoundMaxY", "Max Y", constants.siControlNumber )
oLayout.EndRow()
oLayout.AddRow()
oLayout.AddItem("pBoundMinZ", "Min Z", constants.siControlNumber )
oLayout.AddItem("pBoundMaxZ", "Max Z", constants.siControlNumber )
oLayout.EndRow()
oLayout.EndGroup()
rtn = xsi.InspectObj(oPset, 0, 0, constants.siModal, False)
if not rtn:
return oPset
else:
return
def GetXYZfilePath():
# Setup a simple file browser session to pick .XYZ file
global xyzfileName
global xyzfilePath
initDir = xsi.ActiveProject2.Path
oFilebrowser = XSIUIToolkit.FileBrowser
oFilebrowser.DialogTitle = "Please pick a .xyz file to import..."
oFilebrowser.InitialDirectory = initDir
oFilebrowser.Filter = "XYZ Files(*.xyz)|*.xyz|All Files (*.*)|*.*||"
oFilebrowser.ShowOpen()
xyzfilePath = oFilebrowser.FilePathName
xyzfileName = oFilebrowser.FileBaseName
if xyzfilePath <> "":
return xyzfilePath
else:
return
def GetPointsList(xyzFilePath):
# Open the .XYZ file and read-in all the data.
xyzFile = open(xyzfilePath,"rU")
dataStr = xyzFile.read()
# Setup progress bar for point data parsing in case file is huge
oProgressBar = XSIUIToolkit.ProgressBar
oProgressBar.Maximum = 100
oProgressBar.Caption = "Retrieving Points from .xyz File..."
oProgressBar.Visible = 1
oProgressBar.Value = 100
# Massive regular expression retrieves all vaid point data from the file
pointsList =
re.findall(r"(-*\d+\.\d+|-*\d+\.\d+[Ee]-\d+)\,(-*\d+\.\d+|-*\d+\.\d+[Ee]-\d+)\,(-*\d+\.\d+|-*\d+\.\d+[Ee]-\d+)",
dataStr)
xyzFile.close()
return pointsList
def ParsePoints(pointsList, pointsPerc):
pointDataList = []
nbPoints = len(pointsList)
nbPointsFloat = float(nbPoints)
lineStep =
int(nbPointsFloat/((nbPointsFloat/100)*float(pointsPerc))+0.001)
if lineStep >= 1 and lineStep <= nbPoints:
# Setup progress bar for point data parsing
oProgressBar = XSIUIToolkit.ProgressBar
oProgressBar.Maximum = nbPoints
oProgressBar.Step = lineStep
oProgressBar.Caption = "Parsing Points List..."
oProgressBar.CancelEnabled = 1
oProgressBar.Visible = 1
while oProgressBar.Value < oProgressBar.Maximum and not
oProgressBar.CancelPressed:
lineNo = int(oProgressBar.Value)
# Extract point data from points list
pointTuple = pointsList[lineNo]
# Convert the point position tuple of string data to a
list of floats that have been scaled according to user input
tmpPosition = [v*oPset.pSpatialScale.value for v in
map(float, pointTuple[:3])]
# reorder as XYZ
pointPosition =
[tmpPosition[0],tmpPosition[1],tmpPosition[2]]
filterPoint = oPset.pFilterByBounds.value
# Check if point lies within the user defined bounding
volume
inBounds = CheckWithinBounds(pointPosition)
# Decide whether or not to skip the point if it lies
outside the user defined bounding volume
if ((not filterPoint) or (filterPoint and inBounds)):
# Convert the color tuple of string data to a
list of floats representing the color as Softimage RGB
pointColor = [0,0,0]
# Add a value of 1 as Alpha
pointAlphaValue = float(1)
pointColor.append(pointAlphaValue)
# Append point position and color to
pointDataList
pointDataList.append(pointColor+pointPosition)
oProgressBar.Increment()
else:
pr("Percentage too low!!! No points will be created!!!")
pr("Aborting!!!")
return pointDataList
def CheckWithinBounds(pointPosition):
isWithinBounds = 1
for i in range(0,2):
if pointPosition[0] > oPset.pBoundMaxX.value or
pointPosition[1] > oPset.pBoundMaxY.value or pointPosition[2] >
oPset.pBoundMaxZ.value:
isWithinBounds = 0
if pointPosition[0] < oPset.pBoundMinX.value or
pointPosition[1] < oPset.pBoundMinY.value or pointPosition[2] <
oPset.pBoundMinZ.value:
isWithinBounds = 0
return isWithinBounds
####################################################################################################################################
# ICE CACHE STUFF
####################################################################################################################################
def WriteIceCache(xyzFilePath, pointDataList, pointSize):
fileName, ext = os.path.splitext( xyzFilePath )
icePath1 = fileName + ".1.icecache"
icePath2 = fileName + ".2.icecache"
returnPath = fileName + ".[1..2].icecache"
cachefile1 = gzip.open( icePath1, "wb" )
cachefile2 = gzip.open( icePath2, "wb" )
nbPoints = len(pointDataList)
data = WriteHeader( nbPoints, 3 )
data += WriteAttrDefs()
chunks = GetChunks(nbPoints)
# Colors
for chunk in chunks:
data += pack("I", 0) #is constant?
for i in chunk:
r = pointDataList[i][0]
g = pointDataList[i][1]
b = pointDataList[i][2]
a = pointDataList[i][3]
#pr(str(i) + ": " + str(r) + " --- " + str(g) + " --- "
+ str(b) + " --- " + str(a))
data += pack("4f",r, g, b, a)
# Point positions
data += pack("I", 0) #is constant?
for chunk in chunks:
for i in chunk:
x = pointDataList[i][4]
y = pointDataList[i][5]
z = pointDataList[i][6]
#pr(str(i) + ": " + str(x) + " --- " + str(y) + " --- "
+ str(z))
data += pack("3f",x, y, z)
# Sizes
for chunk in chunks:
data += pack("I", 0) #is constant?
for i in chunk:
data += pack("1f",pointSize)
# Write two cache files.
cachefile1.write( data )
cachefile1.close()
cachefile2.write( data )
cachefile2.close()
return returnPath
def WriteHeader( nbPoints, nbAttributes ):
data = pack( "8s", "ICECACHE" ) #header string
data += pack( "I", 102 ) #version number
data += pack( "I", 0 ) #object type, pointcloud
data += pack( "I", nbPoints ) #point count
data += pack( "I", 0 ) #edge count
data += pack( "I", 0 ) #polygon count
data += pack( "I", 0 ) #sample count
data += pack( "I", 0 ) #don"t know this one
data += pack( "I", nbAttributes ) #attribute count
return data
def WriteAttrDefs():
#particle color
data = pack( "L", 5 ) #attribute name length
data += pack( "8s", "color___" ) #attribute name
data += pack( "I", 512 ) #data type
data += pack( "I", 1 ) #structure type
data += pack( "I", 2 ) #context type
data += pack( "I", 0 ) #database ID, obsolete
data += pack( "I", 2 ) #category
#particle position
data += pack( "L", 13 ) #attribute name length
data += pack( "16s", "pointposition___" ) #attribute name
data += pack( "I", 16 ) #data type
data += pack( "I", 1 ) #structure type
data += pack( "I", 2 ) #context type
data += pack( "I", 0 ) #database ID, obsolete
data += pack( "I", 2 ) #category
#particle size
data += pack( "L", 4 ) #attribute name length
data += pack( "4s", "size" ) #attribute name
data += pack( "I", 4 ) #data type
data += pack( "I", 1 ) #structure type
data += pack( "I", 2 ) #context type
data += pack( "I", 0 ) #database ID, obsolete
data += pack( "I", 2 ) #category
return data
def GetChunks(num):
if num < 4000:
return [range(num)]
outlist = []
chunks = num / 4000
for i in range(chunks):
outlist.append(range((i)*4000, (i+1)*4000))
outlist.append(range( (i+1)*4000, (i+1)*4000 + num%4000) )
return outlist
main()