Marcus H. Mendenhall:
 |>Also, how do you take a vertex list and turn it into a polygon (face,
 |>loop, edges) inside a DX network?
 |>
 |>I found Connect, but it triangulates the area.
 |
 |If you don't _absolutely_ need to do it in DX, I can send you a
 |python package, which is quite short and simple, which generates FLE
 |objects for DX.  It is a kind of minimal package for writing DX files
 |and for easily converting a data into the right structure.  Inside
 |DX, it takes significant juggling (although the algorithm I use in
 |python could probably be done).

Sure, I'd be interested in a copy.

Thanks,OK, I'll post this to the list since it isn't really too long... a quick & dirty python package for writing DX native files and, especially, FLE objects. here it is (as an attachment so that lines don't get wrapped). If anyone (who wants this) has trouble receiving this via the list, I will send it directly.

Marcus Mendenhall
from math import *
from Numeric import *
import Numeric
import struct

class dxfile:
    def __init__(self, filename, mode="ascii"):
        self.mode=mode
        self.binary_data_offset=0
        self.file=open(filename,"w")
        self.binary_data=""

self.typedict={"int":Numeric.Int32,"float":Numeric.Float32,"unsigned byte":Numeric.UnsignedInt8,\ "byte":Numeric.Int8, "short":Numeric.Int16, "complex":Numeric.Complex32}

    def print_array(self, name, type, rank, formatstr, data):
        print >> self.file, "#"
        if rank==1:
            shapestr="shape %d"%len(data[0])
        elif rank==0:
            shapestr=""
        else:
            raise "don't know how to print arrays beyond rank 1"
        if self.mode=="ascii":
print >> self.file, 'object "%s" class array type %s rank %d %s items %d data follows'\
                  %(name, type, rank, shapestr, len(data))
            for i in tuple(data):
                if rank==0:
                    print >> self.file,formatstr%i
                else:
                    print >> self.file, formatstr%tuple(i)
        elif self.mode=="binary":
#determine if we are big-or-little endian, and write file as native for this machine
            endian=struct.unpack("i","\0\0\0\1")
            if endian[0]==1:
                endstr="msb"
            else:
                endstr="lsb"
print >> self.file, 'object "%s" class array type %s rank %d %s items %d %s ieee data %d'\ %(name, type, rank, shapestr, len(data), endstr, len(self.binary_data))

self.binary_data+=array(data).astype(self.typedict[type]).tostring()

def print_FLE_object(self, basename, faces, data, datatype, dataformat, base_data_index=0):
        """facelist consists of a list, each element of which
        consists of a list of loops which comprise the face.
        For Example, a list (((1,2,3),),((2,3,4),),) has two faces,
        one of which is represented by positions object elements 1,2 and 3,
and the second of which is represented by positions 2, 3, and 4, so these
        two faces share an edge along 2,3.  Beware the 1-item lists which
        often appear in the innermost levels here, and require the extra comma
to make sure a list is created. Multiple-item lists in the middle would be used for
        faces with holes, as permitted by the dx FLE spec.
Also, note that the programmer is responsible for writing out the actual positions list to which these objects refer. Since one positions list may be a concatenation of a number of FLE objects, base_data_index can be used to offset all the indices computed in this code to the real start of the object in the positions."""
        edgelist=[]
        looplist=[]
        facelist=[]

        for f in faces:
facelist.append(len(looplist)+base_data_index) #this is where this face begins
            for l in f:
                looplist.append(len(edgelist)+base_data_index)
                for i in l:
                    edgelist.append(i+base_data_index)

        self.print_array(basename+"_edges", "int", 0, "%d", edgelist)
        print  >> self.file, 'attribute "ref" string "positions"'
        self.print_array(basename+"_loops", "int", 0, "%d", looplist)
        print  >> self.file, 'attribute "ref" string "edges"'
        self.print_array(basename+"_faces", "int", 0, "%d", facelist)
        print >> self.file, 'attribute "ref" string "loops"'
        self.print_array(basename+"_data",datatype, 0, dataformat, data)
        print  >> self.file, 'attribute "dep" string "faces"'
        print  >> self.file, "#"
        print  >> self.file, 'object "%s" class field' % basename
        print  >> self.file, 'component "edges" "%s"' % (basename+"_edges")
        print  >> self.file, 'component "data"  "%s"' % (basename+"_data")
        print  >> self.file, 'component "loops" "%s"' % (basename+"_loops")
        print  >> self.file, 'component "faces" "%s"' % (basename+"_faces")

    def print_line(self, string):
        print >> self.file, string

    def close(self):
        self.file.write("end\n"+self.binary_data)
        self.file.close()

def csd(theta):
    return cos(theta*pi/180.0), sin(theta*pi/180.0)

def extrude_poly(poly_data, poly_origin, geometries, cap_ends=0, close_loop=0):
""" takes a single polygon, presumed planar, and creates the appropriate list of faces to connect it to a set of points such that the point poly_origin is translated to each of the centers, then rotated by euler angles theta, eta, phi, (theta=polar angle:0=north, eta=longitude, phi=rotation),
    then scaled by scale, and then connected to the
previous surface where the center, rotation, and scale are in the elements of the geometries list.
    The angles in geometries are specified in degrees"""
    poslist=[]
    faces=[]
    poly_array=array(poly_data,Float)
    sides=len(poly_data)
    slices=len(geometries)
    xyz0=array(poly_origin,Float)
    poly_array[:]=poly_array[:]-xyz0 #translate to origin
poly_array=transpose(poly_array) #transposed array allows dot to transform all coordinates at once
    for (center, euler, scale) in geometries:
        c,s=csd(euler[2])
        phimat=array(((c,s,0),(-s,c,0),(0,0,1)),Float)
        c,s=csd(euler[0])
        thetamat=array(((c,0,s),(0,1,0),(-s,0,c)),Float)
        c,s=csd(euler[1])
        etamat=array(((c,s,0),(-s,c,0),(0,0,1)),Float)
        emat=dot(etamat,dot(thetamat,phimat))*scale
        pt=transpose(dot(emat, poly_array))+center
        ptl=list(pt)
        for i in ptl:
            poslist.append(tuple(i))

#if the structure is to be closed, connect the last poly back to the first, otherwise skip this
    if close_loop:  connections=slices
    else:           connections=slices-1

#index through the rotated polygons, and connect corresponding edges with triangle pairs (since they may not be planar)
    for i in range(connections):
        nextslice=(i+1)%slices
        base1=i*sides
        base2=nextslice*sides
        for j in range(sides):
            corner1=base1+j
            corner2=base1+((j+1)%sides)
            corner3=base2+j
            corner4=base2+((j-1)%sides)
            faces.append(((corner1,corner2,corner3),))
            faces.append(((corner1,corner3,corner4),))

if not(close_loop) and cap_ends: #if the object has ends, put caps on them if requested
        endloop=range(0,sides)
        faces.append((endloop,))
        endloop=range((slices-1)*sides,slices*sides)
        faces.append((endloop,))

    #print >> sys.stderr, poslist, faces

    return poslist, faces

if __name__ == '__main__':

    def dxfile_test():
        dxf=dxfile("test.dx","binary")
        try:
            q=array((1,2,3,4,5,6,7,8,9,10))
            dxf.print_array("data","int",0,"%d",q)
            dxf.print_array("data2","float",0,"%f",q)
        finally:
            dxf.close()


    def fancytest():
        starpoints=6
        loopsteps=1000 #total sections
        loopturns=3.5
        looppitch=5.0 #units/turn
        looptwist=0.5 #degrees/section
        loopradius=3.0
        loopstepdtheta=2*pi*loopturns/loopsteps
        stepsperturn=float(loopsteps)/loopturns

        dtheta=pi/starpoints
        poly=[]
        for i in range(2*starpoints):
            r=(2+(i%2))/3.0
            theta=i*dtheta
            poly.append((r*cos(theta),r*sin(theta),0.0))

        center=(0,0,0)
        geometries=[]

        for i in range(loopsteps):
            theta=i*loopstepdtheta
            x=cos(theta)*loopradius
            z=sin(theta)*loopradius
geometries.append(((x,looppitch*i/stepsperturn, z),(-theta*180/pi,0,looptwist*i), exp(-i*.001) ))

poslist, faces=extrude_poly(poly, center, geometries, cap_ends=1, close_loop=0)

        file=dxfile("dxtest.dx","binary")
        try:

file.print_array("position list","float", 1, "%.3f %.3f %.3f", poslist) file.print_FLE_object("default", faces, range(len(faces)), "int", "%d")
            file.print_line('component "positions" "position list"')

        finally:
            file.close()

    fancytest()

Reply via email to