#lang racket
(require ffi/com)
(require (except-in "../com.rkt" name)
"../base/coord.rkt"
"../base/bounding-box.rkt")
(provide com-object-eq?)
(provide load-autocad-com
ac-active-viewport
ac-all-viewports
ac-intersection
ac-subtraction
ac-union
perspective-off
perspective-on
sky-status-off
sky-status-background
sky-status-background-and-illumination
sun-status-off
sun-status-on
vbCr
optional
object-rotate3d
transform-by
transform
get-ac-cm-color-blue
get-ac-cm-color-green
get-ac-cm-color-red
application-get-ac-cm-color-interface-object
get-target-variable
get-viewctr-variable
get-viewdir-variable
get-viewport-center
set-viewport-center!
get-viewport-height
set-viewport-height!
get-viewport-snap-on
set-viewport-snap-on!
get-viewport-target
set-viewport-target!
get-viewport-width
set-viewport-width!
)
(define ac-active-viewport 0)
(define ac-all-viewports 1)
(define ac-intersection 1)
(define ac-subtraction 2)
(define ac-union 0)
(define optional com-omit)
(define perspective-off 0)
(define perspective-on 1)
(define sky-status-off 0)
(define sky-status-background 1)
(define sky-status-background-and-illumination 2)
(define sun-status-off 0)
(define sun-status-on 1)
(provide window-maximized window-minimized window-normal)
(define window-maximized 3)
(define window-minimized 2)
(define window-normal 1)
(define vbCr "\r\n")
(define autocad-com-msg "Waiting for AutoCAD to be ready...")
(define (autocad-invoke . args)
(error "Finish this for args ~A" args)
(try-exn-connection
autocad-com-msg
(λ () (apply com-invoke args))))
(define application #f)
(define active-document #f)
(define active-modelspace #f)
(define utility #f)
(define (load-autocad-com)
(set! application
(let ((progid (progid->clsid "AutoCAD.Application")))
(with-handlers ((exn?
(λ (e)
(displayln "Starting AutoCAD...")
(com-create-instance progid))))
(com-get-active-object progid))))
(set! active-document
(com-get-property application "ActiveDocument"))
(set! active-modelspace
(com-get-property active-document "ModelSpace"))
(set! utility
(com-get-property active-document "Utility")))
(define-syntax (def-utility stx)
(syntax-case stx ()
((def name ins out)
(syntax/loc stx
(def-com utility name ins out)))))
(define-syntax (def-model stx)
(syntax-case stx ()
((def name ins out)
(syntax/loc stx
(def-com active-modelspace name ins out)))))
(define-syntax (def-doc stx)
(syntax-case stx ()
((def name ins out)
(syntax/loc stx
(def-com active-document name ins out)))))
(define-syntax (def-app stx)
(syntax-case stx ()
((def name ins out)
(syntax/loc stx
(def-com application name ins out)))))
(define-syntax (def-obj stx)
(syntax-case stx ()
((def name (in ...) out)
(syntax/loc stx
(def-com obj name ((obj com) in ...) out)))))
(def-app get-interface-object (string) com)
(provide open-dbx-doc)
(define (open-dbx-doc filename)
(let ((dbx-doc
(get-interface-object
(string-append "ObjectDBX.AxDbDocument."
(substring (acadver) 0 2)))))
(open dbx-doc filename)
dbx-doc))
(define (color<-ac-cm-color col)
(error "To be finished")
(let ((red (get-ac-cm-color-red col))
(green (get-ac-cm-color-green col))
(blue (get-ac-cm-color-blue col)))
(color-of-rgb red green blue)))
(define (ac-cm-color<-color col)
(error "To be finished")
(let-values (((red green blue) (rgb-of-color col)))
(let ((ac-cm-color (application-get-ac-cm-color-interface-object)))
(ac-cm-color-set-rgb! ac-cm-color red green blue)
ac-cm-color)))
(provide boolean-union boolean-intersection boolean-subtraction)
(define (boolean-union obj0 obj1)
(com-invoke obj0 "Boolean" ac-union obj1)
obj0)
(define (boolean-intersection obj0 obj1)
(com-invoke obj0 "Boolean" ac-intersection obj1)
obj0)
(define (boolean-subtraction obj0 obj1)
(com-invoke obj0 "Boolean" ac-subtraction obj1)
obj0)
(def-obj copy () com)
(def-obj delete () void)
(def-obj explode () coms)
(def-obj mirror3d (point point point) com)
(def-obj move (point point) void)
(def-obj rotate3d (point point real) void)
(def-obj scale-entity (point real) void)
(def-obj offset (real) coms)
(provide ac-extend-none ac-extend-this-entity ac-extend-other-entity ac-extend-both)
(define ac-extend-none 0)
(define ac-extend-this-entity 1)
(define ac-extend-other-entity 2)
(define ac-extend-both 3)
(def-obj intersect-with (com integer) coords<-flat-vector-or-false)
(provide copy-objects)
(define (copy-objects from-doc objs [to-doc active-modelspace])
(com-invoke from-doc "CopyObjects" (arr-coms objs) to-doc))
(provide bounding-box)
(define (bounding-box object)
(let ((min-point (box #f))
(max-point (box #f)))
(com-invoke object "GetBoundingBox" min-point max-point)
(make-bbox
(box-corners-pp
(coord<-vector (unbox min-point))
(coord<-vector (unbox max-point))))))
(provide set-x-data)
(define (set-x-data obj types data)
(com-invoke obj "setXData" (type-describe types `(array ,(vector-length types) short-int))
(type-describe data `(array ,(vector-length data) any))))
(provide get-x-data)
(define (get-x-data obj app-name)
(let ((b0 (box #f))
(b1 (box #f)))
(com-invoke obj "GetXData" app-name b0 b1)
(values (unbox b0) (unbox b1))))
(provide set-data! get-data)
(define (x-data-type value)
(cond ((string? value) 1000)
((real? value) 1040)
((integer? value) 1071)
(else
(error 'x-data-type<-value "Unnaceptable value" value))))
(define (set-data! obj data)
(set-x-data obj
(list->vector
(cons 1001 (map x-data-type data))
(cons "Racket" data))))
(define (get-data obj)
(let-values (((types data) (get-x-data obj "Racket")))
(vector->list data)))
(define (object-offset object distance)
(vector->list
(com-invoke object "Offset" (real distance))))
(define (object-rotate3d object point1 point2 rotation-angle)
(begin0
object
(autocad-invoke
object
"Rotate3D"
(point point1)
(point point2)
(real rotation-angle))))
(define-syntax define-object-predicate
(syntax-rules ()
((_ name str)
(begin
(provide name)
(define (name id)
(string=? (object-name id) str))))))
(define-object-predicate 2d-polyline? "AcDb2dPolyline")
(define-object-predicate 3d-face? "AcDbFace")
(define-object-predicate 3d-polyline? "AcDb3dPolyline")
(define-object-predicate 3d-solid? "AcDb3dSolid")
(define-object-predicate arc? "AcDbArc")
(define-object-predicate circle? "AcDbCircle")
(define-object-predicate ellipse? "AcDbEllipse")
(define-object-predicate lightweight-polyline? "AcDbPolyline")
(define-object-predicate line? "AcDbLine")
(define-object-predicate point? "AcDbPoint")
(define-object-predicate region? "AcDbRegion")
(define-object-predicate spline? "AcDbSpline")
(provide curve?)
(define (curve? object)
(member (object-name object)
'("AcDb3dPolyline" "AcDb2dPolyline"
"AcDbArc" "AcDbCircle" "AcDbEllipse"
"AcDbPolyline" "AcDbLine" "AcDbSpline")))
(def-obj section-solid (point point point) com)
(def-obj transform-by (com<-matrix) void)
(define (transform obj matrix)
(transform-by obj matrix)
obj)
(def-obj item (identity) com)
(def-com-property count)
(define (last-item obj)
(item obj (- (count obj) 1)))
(define (created-items obj prev)
(let ((curr (count obj)))
(cond ((< curr prev)
(error 'created-items "Items were eliminated"))
((= curr prev)
(error 'created-items "No new items"))
(else
(for/list ((i (in-range prev curr 1)))
(item obj i))))))
(define (created-item obj prev)
(let ((curr (count obj)))
(cond ((< curr prev)
(error 'created-item "Items were eliminated"))
((= curr prev)
(error 'created-item "No new item"))
((> curr (+ prev 1))
(error 'created-item "More than one new items"))
(else
(item obj prev)))))
(def-com-property center coord<-vector)
(def-com-property closed (boolean boolean))
(def-com-property control-points coords<-flat-vector)
(def-com-property elevation)
(def-com-property end-angle)
(def-com-property end-point coord<-vector)
(def-com-property handle)
(def-com-property material)
(def-com-property m-close (boolean boolean))
(def-com-property n-close (boolean boolean))
(def-com-property object-name)
(def-com-property object-normal coord<-vector)
(def-com-property position coord<-vector)
(def-com-property (circle-radius "Radius") real)
(def-com-property start-angle)
(def-com-property start-point coord<-vector)
(def-com-property true-color (ac-cm-color<-color color<-ac-cm-color))
(def-com-property custom-scale real)
(provide ac-simple-mesh ac-quad-surface-mesh ac-cubic-surface-mesh ac-bezier-surface-mesh)
(define ac-simple-mesh 0)
(define ac-quad-surface-mesh 5)
(define ac-cubic-surface-mesh 6)
(define ac-bezier-surface-mesh 8)
(def-com-property type (integer integer))
(def-com-property visible (boolean boolean))
(def-com-property coordinates coords<-flat-vector)
(def-com-property (2d-coordinates "Coordinates") coords<-vector-xy) (def-com-property (point-coordinates "Coordinates") coord<-vector)
(def-com-property width (number number))
(def-com-property height (number number))
(def-com-property window-state (number number))
(define (ac-cm-color-set-rgb! object red green blue)
(autocad-invoke object "SetRGB" red green blue))
(define (get-ac-cm-color-blue object)
(com-get-property object "Blue"))
(define (get-ac-cm-color-green object)
(com-get-property object "Green"))
(define (get-ac-cm-color-red object)
(com-get-property object "Red"))
(def-obj documents () com)
(def-obj interface-object (string) com)
(define ac-cm-color-name "AutoCAD.AcCmColor.18")
(define (application-get-ac-cm-color-interface-object)
(interface-object application ac-cm-color-name))
(def-doc close (boolean) identity)
(def-doc end-undo-mark () identity)
(def-doc get-variable (string) identity)
(def-doc regen (string) void)
(def-doc send-command (string) void)
(def-doc set-variable (string identity) identity)
(def-doc start-undo-mark () identity)
(provide add-layer)
(define (add-layer name)
(add (layers active-document) name))
(provide get-layer)
(define (get-layer name)
(item (layers active-document) name))
(define-syntax (def-autocad-variable stx)
(syntax-case stx ()
((def name)
(with-syntax ((str (string-upcase (symbol->string (syntax-e #'name)))))
(syntax/loc stx
(def name str))))
((def name str)
(syntax/loc stx
(begin
(provide name)
(define name
(case-lambda
(() (get-variable str))
((val)
(set-variable str val)))))))))
(def-autocad-variable delobj)
(def-autocad-variable loftnormals)
(def-autocad-variable loftang1)
(def-autocad-variable loftang2)
(def-autocad-variable loftmag1)
(def-autocad-variable loftmag2)
(def-autocad-variable loftparam)
(def-autocad-variable nomutt)
(def-autocad-variable perspective)
(def-autocad-variable skystatus)
(def-autocad-variable sunstatus)
(def-autocad-variable cmdecho)
(def-autocad-variable lenslength)
(def-autocad-variable acadver)
(def-autocad-variable clayer)
(def-autocad-variable osmode)
(def-autocad-variable expert)
(def-autocad-variable filedia)
(def-autocad-variable vsmin)
(def-autocad-variable vsmax)
(def-autocad-variable viewsize)
(def-autocad-variable viewctr)
(def-autocad-variable undoctl)
(define target-name "TARGET")
(define (get-target-variable)
(coord<-vector
(get-variable target-name)))
(define view-ctr-name "VIEWCTR")
(define (get-viewctr-variable)
(coord<-vector
(get-variable view-ctr-name)))
(define view-dir-name "VIEWDIR")
(define (get-viewdir-variable)
(coord<-vector
(get-variable view-dir-name)))
(def-com-property active-layer (string string))
(def-com-property layer (string string))
(def-com-property layers)
(def-com-property active-viewport)
(def-com-property materials)
(def-com-property modelspace)
(def-com-property name)
(def-com-property views)
(def-com-property direction coord<-vector)
(def-com-property target coord<-vector)
(def-com-property lens-length (real real))
(def-obj open (string) void)
(def-obj add (string) com)
(provide all-objects)
(define (all-objects [modelspace active-modelspace])
(for/list ((i (in-range 0 (count modelspace) 1)))
(item modelspace i)))
(def-model add-polyline (arr-points) com)
(def-model add-3d-face (point point point point) com)
(def-model add-3d-mesh (integer integer arr-points) com)
(def-model add-3d-poly (arr-points) com)
(def-model add-arc (point radius angle angle) com)
(def-model add-box (point real real real) com)
(def-model add-circle (point radius) com)
(def-model add-cone (point radius real) com)
(def-model add-cylinder (point radius real) com)
(def-model add-ellipse (point point real) com)
(define (variant-double v)
(type-describe (vector (real v) 0.0 0.0) '(variant double)))
(def-model add-extruded-solid ((profile com) (height real) angle) com)
(def-model add-extruded-solid-along-path ((profile com) (path com)) com)
(def-model add-line (point point) com)
(def-model add-point (point) com)
(def-model add-region (arr-coms) coms)
(def-model add-section (point point point) com)
(def-model add-sphere (point radius) com)
(def-model add-spline (arr-points point point) com)
(def-model add-text (string point positive-real) com)
(def-model add-torus (point radius radius) com)
(define (get-viewport-center viewport)
(coord<-vector
(com-get-property viewport "Center")))
(define (set-viewport-center! viewport center)
(com-set-property! viewport "Center" (point center)))
(define (get-viewport-height viewport)
(com-get-property viewport "Height"))
(define (set-viewport-height! viewport height)
(com-set-property! viewport "Height" height))
(define (get-viewport-snap-on viewport)
(com-get-property viewport "SnapOn"))
(define (set-viewport-snap-on! viewport snap-on?)
(com-set-property! viewport "SnapOn" snap-on?))
(define (get-viewport-target viewport)
(coord<-vector
(com-get-property viewport "Target")))
(define (set-viewport-target! viewport target)
(com-set-property! viewport "Target" (point target)))
(define (get-viewport-width viewport)
(com-get-property viewport "Width"))
(define (set-viewport-width! viewport width)
(com-set-property! viewport "Width" width))
(define-syntax (def-cmd stx)
(syntax-case stx ()
((_ name (in ...) body ...)
(syntax/loc stx
(begin
(provide name)
(define (name in ...)
(send-command (string-append body ...))))))))
(define-syntax (def-new-shape-cmd stx)
(syntax-case stx ()
((_ name (in ...) body ...)
(syntax/loc stx
(begin
(provide name)
(define (name in ...)
(let ((prev-count (count active-modelspace)))
(send-command (string-append body ...))
(created-item active-modelspace prev-count))))))))
(define-syntax (def-new-shapes-cmd stx)
(syntax-case stx ()
((_ name (in ...) body ...)
(syntax/loc stx
(begin
(provide name)
(define (name in ...)
(let ((prev-count (count active-modelspace)))
(send-command (string-append body ...))
(created-items active-modelspace prev-count))))))))
(def-new-shape-cmd new-shape-from (str)
str)
(def-new-shapes-cmd new-shapes-from (str)
str)
(def-cmd erase-all () "_.erase _all" vbCr vbCr)
(def-cmd dview-zoom-command (center target lens distance)
(format "_.dview _z ~A _po ~A ~A _d ~A" lens (point-string target) (point-string center) distance)
vbCr)
(def-new-shape-cmd add-cone-frustum (c base-radius top-radius height)
"_.cone "
(point-string c)
(format " ~A _T ~A ~A " base-radius top-radius height))
(def-cmd reset-ucs () "_.ucs _W ")
(def-cmd view-top () "_.-view _top ")
(def-cmd view-wireframe () "_.vscurrent _2dwireframe ")
(def-cmd view-conceptual () "_.vscurrent _conceptual ")
(define (handent-string handle)
(string-append "(handent \"" handle "\")"))
(define (handent object)
(handent-string (handle object)))
(define (handents objects)
(string-join (map handent objects) " "))
(def-cmd union-command (objects)
"_.union " (handents objects) vbCr)
(def-cmd join-command (objects)
"._join " (handents objects) vbCr)
(def-new-shape-cmd spline-command (points v0 v1)
(format "_.spline _mo _Fit ~A ~A~A~A~A"
(point-string (car points))
(if v0 (format "_T ~A " v0) "")
(string-join (map point-string (cdr points)) " ")
vbCr
(if v1 (format "_T ~A " v1) "")))
(provide loftnormals-ruled
loftnormals-smooth-fit
loftnormals-start-cross-section
loftnormals-end-cross-section
loftnormals-start-and-end-cross-section
loftnormals-all-cross-sections
loftnormals-use-draft-angle-and-magnitude)
(define loftnormals-ruled 0)
(define loftnormals-smooth-fit 1)
(define loftnormals-start-cross-section 2)
(define loftnormals-end-cross-section 3)
(define loftnormals-start-and-end-cross-section 4)
(define loftnormals-all-cross-sections 5)
(define loftnormals-use-draft-angle-and-magnitude 6)
(provide loftparam-no-twist
loftparam-align-direction
loftparam-simplify
loftparam-close)
(define loftparam-no-twist 1)
(define loftparam-align-direction 2)
(define loftparam-simplify 4)
(define loftparam-close 8)
(provide loft-objects-string)
(define (loft-objects-string objects solid?)
(format
"._loft _mo ~A ~A~A\n"
(if solid? "_so" "_su")
(handents objects)
vbCr))
(provide loft-objects-guides-string)
(define (loft-objects-guides-string objects guides solid?)
(format
"._loft _mo ~A ~A~A_guides ~A~A\n"
(if solid? "_so" "_su")
(handents objects)
" "
(handents guides)
vbCr))
(provide loft-to-point-string)
(define (loft-to-point-string object point solid?)
(format
"._loft _mo ~A ~A _po ~A~A"
(if solid? "_so" "_su")
(handent object)
(point-string point)
vbCr))
(provide loft-command)
(define (loft-command loft-string normals closed?)
(let ((previous-param (loftparam))
(previous-normals (loftnormals)))
(let ((param
(if closed?
(bitwise-ior previous-param loftparam-close)
(bitwise-and previous-param (bitwise-not loftparam-close)))))
(unless (= previous-param param)
(loftparam param))
(unless (= previous-normals normals)
(loftnormals normals))
(let ((prev (count active-modelspace)))
(send-command loft-string)
(unless (= previous-param param)
(loftparam previous-param))
(unless (= previous-normals normals)
(loftnormals previous-normals))
(singleton-or-union
(created-items active-modelspace prev))))))
(provide sweep-string)
(define (sweep-string object perpendicular? path solid? rotation scale)
(format
"._sweep _mo ~A ~A _A ~A ~A~A~A "
(if solid? "_so" "_su")
(handent object)
(if perpendicular? "Yes" "No")
(if (= scale 1) "" (format "_S ~A " scale))
(if (= rotation 0) "" (format "_T ~A " (radians->degrees rotation)))
(handent path)))
(provide sweep-command)
(define (sweep-command object perpendicular? path solid? rotation scale)
(new-shape-from (sweep-string object perpendicular? path solid? rotation scale)))
(provide extrude-length-string)
(define (extrude-length-string object length solid?)
(format "._extrude _mo ~A ~A ~A "
(if solid? "_so" "_su")
(handent object)
length))
(provide extrude-direction-string)
(define (extrude-direction-string object start-point end-point solid?)
(format "._extrude _mo ~A ~A _d ~A ~A "
(if solid? "_so" "_su")
(handent object)
(point-string start-point)
(point-string end-point)))
(provide extrude-command-length)
(define (extrude-command-length object length solid?)
(new-shapes-from (extrude-length-string object length solid?)))
(provide extrude-command-direction)
(define (extrude-command-direction object start-point end-point solid?)
(new-shapes-from (extrude-direction-string object start-point end-point solid?)))
(provide revolve-string)
(define (revolve-string object axis-p0 axis-p1 a0 a1 solid?)
(format "_.revolve _mo ~A ~A~A~A ~A _start ~A ~A\n"
(if solid? "_so" "_su")
(handent object)
vbCr
(point-string axis-p0)
(point-string axis-p1)
(radians->degrees a0) (radians->degrees (- a1 a0))))
(provide revolve-command)
(define (revolve-command object axis-p0 axis-p1 fi d-fi solid?)
(new-shape-from (revolve-string object axis-p0 axis-p1 fi d-fi solid?)))
(provide slice-command)
(define (slice-command object p0 p1 p2 in)
(send-command
(format "_.slice ~A~A_3P ~A ~A ~A ~A\n"
(handent object)
vbCr
(point-string p0)
(point-string p1)
(point-string p2)
(point-string in)))
object)
(define (slice-command object p n)
(send-command
(format "_.slice ~A~A_zaxis ~A ~A ~A\n"
(handent object)
vbCr
(point-string p)
(point-string (+c p n))
(point-string (-c p n))))
object)
(provide closed-lines-points)
(define (closed-lines-points ls)
(let loop ((chain (list (end-point (car ls)) (start-point (car ls)))) (ls (cdr ls)))
(if (null? ls)
(reverse chain)
(let ((end (car chain)))
(let ((next (findf (lambda (l1) (=c? end (start-point l1))) ls)))
(if next
(loop (cons (end-point next) chain) (remq next ls))
(error 'closed-lines-points "Missing line segment")))))))
(provide 2dpoly<-3dpoly)
(define (2dpoly<-3dpoly 3dpoly)
(let ((pts (coordinates 3dpoly))
(closed? (closed 3dpoly)))
(let ((2dpoly (add-polyline (if closed? (append pts (list (car pts))) pts))))
(when closed?
(closed 2dpoly #t))
2dpoly)))
(def-utility get-point (#:opt point string) coord<-vector)
(provide get-entity)
(define (get-entity [str "Select shape"])
(define point (box (vector 0.0 0.0 0.0)))
(com-invoke utility "GetEntity" point str))
(def-utility get-integer (#:opt string) number)
(def-utility get-real (#:opt string) number)
(provide singleton-or-union)
(define (singleton-or-union lst)
(cond ((null? lst)
(error 'singleton-or-union "Empty list"))
((null? (cdr lst))
(car lst))
(else
(union-command lst))))
(provide undo-off)
(define (undo-off)
(unless (even? (undoctl))
(send-command (format "_.undo _C _None\n"))))
(provide undo-on)
(define (undo-on)
(when (even? (undoctl))
(send-command (format "_.undo _All\n"))))
(def-cmd render-command (quality width height filename)
(format "._-render ~A R ~A ~A yes ~A\n" quality width height filename))
(provide save-screen-png)
(define (save-screen-png filename)
(let ((filename (string-append filename ".png")))
(let ((prev-filedia (filedia)))
(filedia 0)
(when (file-exists? filename)
(delete-file filename))
(send-command
(format "_.pngout ~A ~A"
filename
vbCr))
(filedia prev-filedia))))
(provide save-screen-eps)
(define (save-screen-eps filename)
(let ((filename (string-append filename ".eps")))
(let ((prev-filedia (filedia)))
(filedia 0)
(when (file-exists? filename)
(delete-file filename))
(send-command
(format "_.PSOUT ~A ~A D N M 1 1=1 5000,5000\n" filename vbCr))
(filedia prev-filedia))))
(define (save-eps filename)
(let ((filename (string-append filename ".eps")))
(let ((prev-filedia (filedia)))
(filedia 0)
(when (file-exists? filename)
(delete-file filename))
(send-command
(format "_.PSOUT ~A ~A D N M 1 1=1 5000,5000\n" filename vbCr))
(filedia prev-filedia))))
(provide view-parameters)
(define (view-parameters)
(send-command "-VIEW _S foo\n")
(let ((view (last-item (views active-document))))
(begin0
(list (direction view)
(target view)
(let-values (((types data) (get-x-data view "ACAD")))
data))
(delete view)
)))
(provide 2d-view)
(define (2d-view [center #f] [magnification #f])
(if center
(zoom-center center magnification)
(values (apply xyz (vector->list (viewctr)))
(viewsize))))
(def-app zoom-all () void)
(def-app zoom-center (point real) void)
(def-app zoom-extents () void)
(provide window-size)
(define (window-size [new-width #f] [new-height #f])
(if new-width
(begin
(width application new-width)
(height application new-height))
(values
(width application)
(height application))))
(provide window-status)
(define (window-status [state #f])
(if state
(window-state application state)
(window-state application)))