; This program runs through the current drawing finding all objects that it
; can extract to a Radiance input file. The layer information is used as the
; material type in Radiance
; The following mappings are implemented at the moment
; AutoCAD   to   Radiance
; 3DFACE    --   polygon
; LINE      --   polygon
; CIRCLE    --   cylinder
; 3DLINE    --   cylinder
; POINT     --   sphere
;
; Load the program into AutoCAD by typing the following from Command:
;
; (load "acad2rad")
;
; Run by typing this command from the AutoCAD Command:
;
; acad2rad
;
; Also included is a utility called xpld. This program runs through the
; drawing exploding all polylines into their component lines and 3dfaces
; Run by typing
;
; xpld
;
; by Robert Amor on 12-Aug-90, final tidyup 22-Oct-90
; Mail:   School of Architecture
;         Victoria University of Wellington
;         PO Box 600
;         Wellington
;         New Zealand
; Phone:  +64 4 721 000 x8008
; FAX:    +64 4 712 070
; E-mail: trebor@comp.vuw.ac.nz

;==============================================
; Get all the 3D faces from the current drawing

(defun get3dface (fname)
  ; ssget extracts all entities of a certain type ie 3DFACE
  (setq faces (ssget "X" (list (cons 0 "3DFACE"))))
  ; make sure that some faces exist
  (cond ((/= faces nil)
    ; find out how many entities there are in the set
    (setq slen (sslength faces))
    (princ "3DFACE: ")
    (princ slen)
    (princ " being processed.\n")
    ; loop through each face found, extract the right info and print it
    (setq obj 0)
    (while (< obj slen)
      (faceproc faces obj)
      (setq obj (1+ obj))
      )
    )
  (t nil)
  )
)

;----------------------------------------------------------------------
; For each 3DFACE in the set, get the layer info and its 4 co-ordinates

(defun faceproc (faces obj)
  ; find the object number of this face
  (setq face (ssname faces obj))
  ; get the list of attributes for this face
  (setq fdata (entget face))
  ; find the layer in the list, remember that the elements in
  ; the list are keyed by the DXF file numbers for the attribute
  (setq layer (cdr (assoc 8 fdata)))
  ; find points 1 through 4 from the list
  (setq p1 (cdr (assoc 10 fdata)))
  (setq p2 (cdr (assoc 11 fdata)))
  (setq p3 (cdr (assoc 12 fdata)))
  (setq p4 (cdr (assoc 13 fdata)))
  ; print out all the extracted information
  (prinfaces layer p1 p2 p3 p4 obj fname)
)

;-------------------------------------------
; Print out the info from a face to the file

(defun prinfaces (layer p1 p2 p3 p4 obj fname)
  ; print the layer name as a material type in Radiance
  (princ layer fname)
  ; print the object type, and construct a unique number for it
  (princ " polygon poly_" fname)
  (princ (1+ obj) fname)
  (princ "\n" fname)
  ; print the info lines as specified in Radiance manual for polygon
  (princ "0\n" fname)
  (princ "0\n" fname)
  (princ "12\n" fname)
  ; process each point seperately
  (prinpoint p1 fname)
  (prinpoint p2 fname)
  (prinpoint p3 fname)
  (prinpoint p4 fname)
  (princ "\n" fname)
)

;=======================================================================
; Get all the circles from the current drawing, turn them into cylinders
; NOTE: circle must have thickness  thickness=radius of cylinder

(defun getcircle (fname)
  ; ssget extracts all entities of a certain type ie CIRCLE
  (setq circles (ssget "X" (list (cons 0 "CIRCLE"))))
  (cond ((/= circles nil)
    ; find out how many entities there are in the set
    (setq slen (sslength circles))
    (princ "CIRCLE: ")
    (princ slen)
    (princ " being processed.\n")
    ; loop through each circle found, extract the right info and print it
    (setq obj 0)
    (while (< obj slen)
      (circleproc circles obj)
      (setq obj (1+ obj))
      )
    )
  (t nil)
  )
)

;--------------------------------------------------------------------
; For each CIRCLE in the set, get the layer info and its co-ordinates

(defun circleproc (circles obj)
  ; find the object number of this circle
  (setq circle (ssname circles obj))
  ; get the list of attributes for this circle
  (setq cdata (entget circle))
  ; find the thickness of the circle to generate the ring radius
  ; remember that the elements in
  ; the list are keyed by the DXF file numbers for the attribute
  (setq thickness (cdr (assoc 39 cdata)))
  ; check thickness is greater than 0
  (cond ((> thickness 0)
    ; find the layer the circle is on
    (setq layer (cdr (assoc 8 cdata)))
    ; find center of circle
    (setq p1 (cdr (assoc 10 cdata)))
    ; find the radius of the circle
    (setq radius (cdr (assoc 40 cdata)))
    ; find the plane normal of the circle
    (setq plane (cdr (assoc 210 cdata)))
    ; print out all the extracted information
    (princircles layer thickness p1 radius plane obj fname)
    )
  (t nil)
  )
)

;------------------------------------------------
; Print out the info from the circles to the file

(defun princircles (layer thickness p1 radius plane obj fname)
  ; print the layer name as a material type in Radiance
  (princ layer fname)
  ; print the object type, and construct a unique number for it
  (princ " cylinder cyl_circ_" fname)
  (princ (1+ obj) fname)
  (princ "\n" fname)
  ; print the info lines as specified in Radiance manual for ring
  (princ "0\n" fname)
  (princ "0\n" fname)
  (princ "7\n" fname)
  ; print one end of the cylinder
  (prinpoint p1 fname)
  ; find the length of the cylinder by multiplying the thickness by the normal vector
  (setq lv (list (* thickness (car plane)) (* thickness (cadr plane)) (* thickness (caddr plane))))
  ; add the width to the previous point to find the end of the cylinder
  (setq p2 (list (+ (car p1) (car lv)) (+ (cadr p1) (cadr lv)) (+ (caddr p1) (caddr lv))))
  (prinpoint p2 fname)
  (princ "   " fname)
  (princ thickness fname)
  (princ "\n" fname)
  (princ "\n" fname)
)

;===================================================================
; Get all 3dlines from the current drawing, turn them into cylinders
; NOTE: line must have thickness  thickness=radius  line=centreline

(defun get3dline (fname)
  ;ssget extracts all entities of a certain type ie 3DLINE
  (setq lines (ssget "X" (list (cons 0 "3DLINE" ))))
  (cond ((/= lines nil)
    ;find out how many entities there are in the set
    (setq slen (sslength lines))
    (princ "3DLINE: ")
    (princ slen)
    (princ " being processed.\n")
    ;loop through each line found, extract the right info and print
    (setq obj 0)
    (while (< obj slen)
      (line3dproc lines obj)
      (setq obj (1+ obj))
      )
    )
  (t nil)
  )
)

;-------------------------------------------------------------------
; for each 3DLINE in the set, get the layer info and its coordinates

(defun line3dproc (lines obj)
  ; find the object number of this line
  (setq line (ssname lines obj))
  ;get the list of attributes for this line
  (setq ldata (entget line))
  ; find the thickness of the line to generate the cylinder radius
  ; remember that elements in the list are keyed
  ; by the DXF file numbers for the attribute
  (setq thickness (cdr (assoc 39 ldata)))
  ; check thickness of line is greater than 0
  (cond ((> thickness 0)
    ; find the layer of this line
    (setq layer (cdr (assoc 8 ldata)))
    ;find startpoint of line
    (setq p1 (cdr (assoc 10 ldata)))
    ;find endpoint of line
    (setq p2 (cdr (assoc 11 ldata)))
    ; print out all the extracted information
    (prin3dlines layer p1 p2 thickness obj fname)
    )
  (t nil)
  )
)

;----------------------------------------------
;Print out the info from the 3dlines to the files

(defun prin3dlines (layer p1 p2 thickness obj fname)
  ; print the layer name as a material type in Radiance
  (princ layer fname)
  ; print the object type and construct a unique number for it
  (princ " cylinder cyl_3d_" fname)
  (princ (1+ obj) fname)
  (princ "\n" fname)
  ; print the info lines as specified in Radiance manual for cylinder
  (princ "0\n" fname)
  (princ "0\n" fname)
  (princ "7\n" fname)
  ;process each point separately
  (prinpoint p1 fname)
  (prinpoint p2 fname)
  (princ "   " fname)
  (princ thickness fname)
  (princ "\n\n" fname)
)

;================================================================
; Get all points from the current drawing, turn them into spheres
; NOTE: point must have thickness  thickness=radius

(defun getpoint (fname)
  ;ssget extracts all entities of a certain type ie POINT
  (setq points (ssget "X" (list (cons 0 "POINT" ))))
  (cond ((/= points nil)
    ;find out how many entities there are in the set
    (setq slen (sslength points))
    (princ "POINT: ")
    (princ slen)
    (princ " being processed.\n")
    ;loop through each point found, extract the right info and print
    (setq obj 0)
    (while (< obj slen)
      (pointproc points obj)
      (setq obj (1+ obj))
      )
    )
  (t nil)
  )
)

;-------------------------------------------------------------------
; for each POINT in the set, get the layer info and its coordinates

(defun pointproc (points obj)
  ; find the object number of this point
  (setq point (ssname points obj))
  ;get the list of attributes for this point
  (setq pdata (entget point))
  ; find the thickness of the point to generate the sphere radius
  ; remember that elements in the list are keyed
  ; by the DXF file numbers for the attribute
  (setq thickness (cdr (assoc 39 pdata)))
  ; check thickness of point is greater than 0
  (cond ((> thickness 0)
    ; find the layer of this point
    (setq layer (cdr (assoc 8 pdata)))
    ;find center of point
    (setq p1 (cdr (assoc 10 pdata)))
    ; print out all the extracted information
    (prinpoints layer p1 thickness obj fname)
    )
  (t nil)
  )
)

;--------------------------------------------
; Print out the info from a point to the file

(defun prinpoints (layer p1 thickness obj fname)
  ; print the layer name as a material type in Radiance
  (princ layer fname)
  ; print the object type and construct a unique number for it
  (princ " sphere sphere_" fname)
  (princ (1+ obj) fname)
  (princ "\n" fname)
  ; print the info lines as specified in Radiance manual for sphere
  (princ "0\n" fname)
  (princ "0\n" fname)
  (princ "4\n" fname)
  ; print out the center of the sphere
  (prinpoint p1 fname)
  (princ "   " fname)
  (princ thickness fname)
  (princ "\n\n" fname)
)

;========================================================================
; Get all lines from the current drawing, turn them into 3d-faces
; NOTE: line must have thickness  thickness=width of face in direction of
;       line normal

(defun getline (fname)
  ;ssget extracts all entities of a certain type ie LINE
  (setq lines (ssget "X" (list (cons 0 "LINE" ))))
  (cond ((/= lines nil)
    ;find out how many entities there are in the set
    (setq slen (sslength lines))
    (princ "LINE: ")
    (princ slen)
    (princ " being processed.\n")
    ;loop through each line found, extract the right info and print
    (setq obj 0)
    (while (< obj slen)
      (lineproc lines obj)
      (setq obj (1+ obj))
      )
    )
  (t nil)
  )
)

;-------------------------------------------------------------------
; for each LINE in the set, get the layer info and its coordinates

(defun lineproc (lines obj)
  ; find the object number of this line
  (setq line (ssname lines obj))
  ;get the list of attributes for this line
  (setq ldata (entget line))
  ; find the thickness of the line to generate the width of the face
  ; remember that elements in the list are keyed
  ; by the DXF file numbers for the attribute
  (setq thickness (cdr (assoc 39 ldata)))
  ; check thickness of line is greater than 0
  (cond ((> thickness 0)
    ; find the layer of this line
    (setq layer (cdr (assoc 8 ldata)))
    ;find startpoint of line
    (setq p1 (cdr (assoc 10 ldata)))
    ;find endpoint of line
    (setq p2 (cdr (assoc 11 ldata)))
    ; get the normal vector of the thickness
    (setq normal (cdr (assoc 210 ldata)))
    ; print out all the extracted information
    (prinlines layer p1 p2 thickness normal obj fname)
    )
  (t nil)
  )
)

;----------------------------------------------
;Print out the info from the lines to the files

(defun prinlines (layer p1 p2 thickness normal obj fname)
  ; print the layer name as a material type in Radiance
  (princ layer fname)
  ; print the object type and construct a unique number for it
  (princ " polygon thick_line_" fname)
  (princ (1+ obj) fname)
  (princ "\n" fname)
  ; print the info lines as specified in Radiance manual for polygon
  (princ "0\n" fname)
  (princ "0\n" fname)
  (princ "12\n" fname)
  ;process each point separately
  (prinpoint p1 fname)
  (prinpoint p2 fname)
  ; find the width of the face by multiplying the thickness by the normal vector
  (setq lv (list (* thickness (car normal)) (* thickness (cadr normal)) (* thickness (caddr normal))))
  ; add the width to the previous point to find the third point on the face
  (setq p3 (list (+ (car p2) (car lv)) (+ (cadr p2) (cadr lv)) (+ (caddr p2) (caddr lv))))
  ; add the width to the first point to find the last point on the face
  (setq p4 (list (+ (car p1) (car lv)) (+ (cadr p1) (cadr lv)) (+ (caddr p1) (caddr lv))))
  (prinpoint p3 fname)
  (prinpoint p4 fname)
  (princ "\n" fname)
)

;==================================================================
; Print out the info for a single point, ie a list of three numbers
; in the Radiance style

(defun prinpoint (point fname)
  (princ "   " fname)
  ; print out the x co-ordinate
  (princ (car point) fname)
  (princ "   " fname)
  ; print out the y co-ordinate
  (princ (cadr point) fname)
  (princ "   " fname)
  ; print out the z co-ordinate
  (princ (caddr point) fname)
  (princ "\n" fname)
)

;===========================================================================
; Define a procedure to explode a polyline into its component lines or faces

(defun polyproc (polys obj)
  ; find the object number of this polyline
  (setq poly (ssname polys obj))
  ; explode the polyline into its components
  (command "explode" poly)
)

(defun C:XPLD ()
  ; ssget extracts all entities of a certain type ie POLYLINE
  (setq polys (ssget "X" (list (cons 0 "POLYLINE"))))
  ; make sure that some polys exist
  (cond ((/= polys nil)
    ; find out how many entities there are in the set
    (setq slen (sslength polys))
    (princ "POLYLINE: ")
    (princ slen)
    (princ " being exploded.\n")
    ; loop through each poly found, extract the right info and explode it
    (setq obj 0)
    (while (< obj slen)
      (polyproc polys obj)
      (setq obj (1+ obj))
      )
    )
  (t
   (princ "No POLYLINE\n"))
  )
)

;============================================================
; Process the drawing file, ask for a file name to create and
; process the types defined,

(defun C:ACAD2RAD ()
  ; get the name of the file to create
  (setq file (getstring "\nWhat Radiance file to create: "))
  ; open the file to write to
  (setq fname (open file "w"))
  ; process all supported types
  (get3dface fname)
  (getcircle fname)
  (get3dline fname)
  (getpoint  fname)
  (getline   fname)
  ; ALL NEW PROCEDURES TO EXTRACT OTHER TYPES OF OBJECTS FROM AUTOCAD
  ; SHOULD BE CALLED FROM HERE, AND FOLLOW THE STRUCTURE OF THE
  ; PROCEDURES DEFINED ABOVE
  ;
  (princ "Done\n")
  ; close the file after we have finished writing everything to it
  (close fname)
)