Visual LISP, AutoLISP and General Customization
cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 

ForEach on Selection Set

13 REPLIES 13
Reply
Message 1 of 14
Anonymous
4171 Views, 13 Replies

ForEach on Selection Set

I am trying to improve my language skills and the Lamda, Mapcar, and ForEach functions are still a little foreign to me. I am getting of subject. The main reason I am posting is I wondered if there is a way to go through a selection set faster than Repeat or While? Also, if some have easy to follow, useful examples of the above functions it would be appreciated. Thanks. Joshua Modglin
13 REPLIES 13
Message 2 of 14
Anonymous
in reply to: Anonymous

Hi Joshua

I dont know a different way with selection sets but maybe you can
optimize it a little bit...

(while (setq CurEnt (ssname CurSet 0))
(DoYourStuffWith CurEnt)
...
(ssdel CurEnt CurSet)
)

Cheers
--
Juerg Menzi
MENZI ENGINEERING GmbH, Switzerland
http://www.menziengineering.ch
Message 3 of 14
Anonymous
in reply to: Anonymous

Josh,

I'm sure I am not the most qualified to answer this question but here are a
couple of simple examples. Each of these does the same thing, add 1 to each
element in the list and return the result as a list.

(foreach x '(1 2 3 4 5) (setq Rtn (cons (1+ x) Rtn)))
(reverse Rtn)

(mapcar '1+ '(1 2 3 4 5))

(mapcar '(lambda (x) (+ 1 x)) '(1 2 3 4 5))


I know of no other way to process a selection set other than (repeat) or
(while). I remember seeing Bobby Jones give some excellent tutorials on
(mapcar) and (lambda), you might try and dig though the past threads.


--
-Jason

Member of the Autodesk Discussion Forum Moderator Program


> I am trying to improve my language skills and the Lamda, Mapcar, and
ForEach functions are still a little foreign to me. I am getting of subject.
The main reason I am posting is I wondered if there is a way to go through a
selection set faster than Repeat or While? Also, if some have easy to
follow, useful examples of the above functions it would be appreciated.
Message 4 of 14
Anonymous
in reply to: Anonymous

Oops... forgot ActiveX...

Check my homepage -> Free Stuff and search for 'VxSsetSelect',
'VxSsetMake' and 'VxSsetFilter'.

Cheers
--
Juerg Menzi
MENZI ENGINEERING GmbH, Switzerland
http://www.menziengineering.ch
Message 5 of 14
Anonymous
in reply to: Anonymous

Try these links...

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&threadm=E624F814DAFDE4C99
C963BDC1FE3D2D8%40in.WebX.maYIadrTaRb&rnum=2&prev=/groups%3Fq%3Dmapcar%2Bgro
up:autodesk.autocad.customization%2Bauthor:Bobby%2Bauthor:Jones%26hl%3Den%26
lr%3D%26ie%3DUTF-8%26selm%3DE624F814DAFDE4C99C963BDC1FE3D2D8%2540in.WebX.maY
IadrTaRb%26rnum%3D2

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&threadm=15A34522E8534F78E
D7B86DE46961F38%40in.WebX.maYIadrTaRb&rnum=1&prev=/groups%3Fq%3Dmapcar%2Bgro
up:autodesk.autocad.customization%2Bauthor:Bobby%2Bauthor:Jones%26hl%3Den%26
lr%3D%26ie%3DUTF-8%26selm%3D15A34522E8534F78ED7B86DE46961F38%2540in.WebX.maY
IadrTaRb%26rnum%3D1



--
-Jason

Member of the Autodesk Discussion Forum Moderator Program


> I remember seeing Bobby Jones
Message 6 of 14
Anonymous
in reply to: Anonymous

;found on net
; sorry don't remember the author, please stand up and take a bow if you're
listening
; you could probably find it through google
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
(defun FOR-SSET (sset f / n)
(if (= 'PICKSET (type sset))
(repeat (progn (setq n -1) (fix (sslength sset)))
(f (ssname sset (setq n (1+ n)))))))

;;;Use thus:
;;;
;;;(for-sset (ssget ...)
;;; (lambda(e / locals...)
;;; .... ))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;

still uses repeat but packages it conveniently for you.

I have found that reading and re-reading and re-reading the docs on lambda
mapcar etc was the only way to gradually absorb these initially confusing
functions - oh yeah and try lots of simple examples to get it 'in your
hands'. (they do get easy once you "get it")
Search google for these, some of the 'masters' have posted excellent
tutorials on these in recent months or at least in the past year or so.

an example:
From: "Doug Broad"
Subject: Re: Mapcar mistery
Date: Wednesday, November 07, 2001 12:14 PM

I was wrong about the quote list being returned

Here's a command log. Perhaps that will clarify.

Command: (setq table '(( a b c d )( 1 2 3 4)))
((A B C D) (1 2 3 4))

Command: (mapcar 'list table)
(((A B C D)) ((1 2 3 4)))

Command: (apply 'mapcar (cons 'list table))
((A 1) (B 2) (C 3) (D 4))

Command: (mapcar 'list (car table)(cadr table))
((A 1) (B 2) (C 3) (D 4))

By using the apply function, a list of lists (i.e. table in this case)
can be operated on so that mapcar relates not to the top
level of the elements of the list but to the second level elements.
The concept could be expanded further to make a more
generalized function

Command: (defun mapcaar (f l)(apply 'mapcar (cons f l)))
MAPCAAR
Command: (mapcaar 'list table)
((A 1) (B 2) (C 3) (D 4))
Command: (mapcaar 'cons table)
((A . 1) (B . 2) (C . 3) (D . 4))
Command: (mapcaar 'set table)
(1 2 3 4)
Command: !a
1
Command: !b
2
Command: !c
3
Command: !d
4
Command: (mapcaar '(lambda (x y) (+ (eval x) y)) table)
(2 4 6 😎

Hope that answers more questions than it raises. Apply lets
mapcar work on subelements. Can you think of a way to
let mapcar work on the sub-sub elements of a list?

Doug

"J. Avelar" wrote in message
news:42BE6B74CE9E5E79D7798C80DC372C8A@in.WebX.maYIadrTaRb...
> Hi Doug,
>
> Thanks for the reply, but I still have some doubts.
>
> I typed (cons 'list table) and it returned something slightly different
from
> ('list (a b c d) (1 2 3 4)), it returned (LIST (a b c d) (1 2 3 4)). Note
> the absence of '.
>
> Sorry I still don't get he difference between apply 'mapcar and just
> mapcar. Doesn't mapcar performs a function to a list?
>
> In this case, is LIST the function it performs on the list?
>
> Thanks again.
>
> Doug Broad escreveu nas notícias de
> mensagem:82DA36C67F0852EDE1B75FEB5C46EA98@in.WebX.maYIadrTaRb...
> > (apply 'mapcar (cons 'list table))
> >
> > 1. (cons 'list table) builds the arguments for the mapcar function
> > returns ('list (a b c d) (1 2 3 4))
> >
> > 2. (apply 'mapcar ... applies the mapcar function to the list of
> > arguments. It effectively builds and evaluates the following:
> > (mapcar 'list (a b c d) (1 2 3 4))
> >
> > 3. If table always contains 2 elements, it could have also been
> > written:
> > (mapcar 'list (car table)(cadr table))
> >
> > Doug
> >
> >
Message 7 of 14
Anonymous
in reply to: Anonymous

I don't know (or care) about speed but since selection sets in vlisp are
collection objects you can use (vlax-map-collection) and (vlax-for) on them.
Makes the coding a little cleaner. Look at Juerg's functions to see how to
make an activex selectionSet. Here is a little sample function. Load it,
grip some objects, and run SST.

(defun c:sst ( / vlss)
(setq
vlss (vla-get-pickFirstSelectionSet (vla-get-activedocument
(vlax-get-acad-object)))
)
(vlax-map-collection vlss 'vlax-dump-object)
)

--
Cliff

"jmodglin" wrote in message
news:f0ff75a.-1@WebX.maYIadrTaRb...
> I am trying to improve my language skills and the Lamda, Mapcar, and
ForEach functions are still a little foreign to me. I am getting of subject.
The main reason I am posting is I wondered if there is a way to go through a
selection set faster than Repeat or While? Also, if some have easy to
follow, useful examples of the above functions it would be appreciated.
Thanks. Joshua Modglin
>
Message 8 of 14
Anonymous
in reply to: Anonymous

Those links were all "live" when I posted them, sorry about that.

--
-Jason

Member of the Autodesk Discussion Forum Moderator Program


> Try these links...
Message 9 of 14
Anonymous
in reply to: Anonymous

another blast from the past

From: "Vladimir Nesterovsky"
Subject: Re: Mapcar mistery
Date: Wednesday, November 07, 2001 8:57 PM

J. Avelar wrote in message
news:42BE6B74CE9E5E79D7798C80DC372C8A@in.WebX.maYIadrTaRb...
> Hi Doug,
>
> Thanks for the reply, but I still have some doubts.
>
> I typed (cons 'list table) and it returned something slightly different
from
> ('list (a b c d) (1 2 3 4)), it returned (LIST (a b c d) (1 2 3 4)). Note
> the absence of '.
>
> Sorry I still don't get he difference between apply 'mapcar and just
> mapcar. Doesn't mapcar performs a function to a list?
>
> In this case, is LIST the function it performs on the list?
>

EXACTLY. Mapcar expects a symbol which must be a function's name.
It interprets it as such and applies the function on arguments it's supplied
in a list. So the symbol LIST is used as a function name here. When it is
printed, it is printed as LIST. Would we type it like (list 1 2 3), it would
be
interpreted as a function call by Autolisp system. If lst is '(1 2 3),
(cons 'list lst) will produce (LIST 1 2 3), etc...

Apply feeds each element in a list as separate function argument to a
function
it is called with, it kind of "opens the parentheses". So when we write
(apply 'mapcar (cons 'list tbl)) it's equivalent to
(mapcar 'list (car tbl) (cadr tbl) (nth 2 tbl) (nth 3 tbl) ...... (last
tbl) )

Apply doesn't care that the symbol 'LIST names a function, all it sees
is a list of symbol LIST and then some lists (top elements of table which is
a list of lists). Then, when mapcar goes into action, it sees the symbol
LIST
and uses it as a name of a function, namely, the function LIST.

What makes such code possible, is that in Lisp, code is data, and data is
code.


Happy lisping,
--
Have fun, 🙂
Vlad http://vnestr.tripod.com/
(define (average . args)
(if args (/ (apply '+ args) (length args))))
Message 10 of 14
Anonymous
in reply to: Anonymous

Joshua Modglin

Here are some very useful functions by

Tom Berger

;;; START *******************************************************

;;; mapent is to selection sets what mapcar is to lists:
(defun ss_mapent (function ss / i)
(repeat (setq i (sslength ss))
((lambda (proc args / ss function i)
(apply proc args)
)
function
(list (ssname ss (setq i (1- i))))
)
)
)

(defun ss_modent (ss dxf val / old)
(ss_mapent
'(lambda (ename)
(if (setq old (assoc dxf (entget ename)))
(entmod (subst (cons dxf val) old (entget ename)))
(entmod (cons (cons dxf val) (entget ename)))
)
)
ss
)
)


(defun ss_featurelist (ss dxf / res result)
(if (= 'PICKSET (type ss))
(ss_mapent
'(lambda (ename)
(if (setq res (cdr (assoc dxf (entget ename))))
(if (member res result)
nil
(setq result (cons res result))
)
)
)
ss
)
)
result
)


(defun ss_union (set1 set2 / set3) ;;;Vereinigung
(setq set3 (ssadd))
(if (and (= 'PICKSET (type set1)) (= 'PICKSET (type set2)))
(progn
(ss_mapent
'(lambda (x)
(setq set3 (ssadd x set3))
)
set1
)
(ss_mapent
'(lambda (x)
(setq set3 (ssadd x set3))
)
set2
)
)
)
set3
)


(defun ss_subtract (set1 set2 / set3) ;;;Differenz
(setq set3 (ssadd))
(if (and (= 'PICKSET (type set1)) (= 'PICKSET (type set2)))
(progn
(ss_mapent
'(lambda (x)
(setq set3 (ssadd x set3))
)
set1
)
(ss_mapent
'(lambda (x)
(if (ssmemb x set3)
(setq set3 (ssdel x set3))
)
)
set2
)
)
)
set3
)


(defun ss_intersect (set1 set2 / set3) ;; Schnittmenge
(setq set3 (ssadd))
(if (and (= 'PICKSET (type set1)) (= 'PICKSET (type set2)))
(ss_mapent
'(lambda (x)
(if (ssmemb x set2)
(setq set3 (ssadd x set3))
)
)
set1
)
)
set3
)


(defun ss_xor (set1 set2 / set3) ;;Vereinigung ohne Schnittmenge (setq set3
(ssadd))
(if (and (= 'PICKSET (type set1)) (= 'PICKSET (type set2)))
(progn
(ss_mapent
'(lambda (x)
(if (ssmemb x set2)
nil
(setq set3 (ssadd x set3))
)
)
set1
)
(ss_mapent
'(lambda (x)
(if (ssmemb x set1)
nil
(setq set3 (ssadd x set3))
)
)
set2
)
)
)
set3
)


(defun ss_newset (en / nset) ;; alle Entities, die seit EN erzeugt wurden.
Wenn EN = NIL, dann alle !
(setq nset (ssadd))
(if en
(while (setq en (entnext en))
(if (member (cdr (assoc 0 (entget en))) '("VERTEX" "SEQEND")) nil
(setq nset (ssadd en nset))
)
)
(setq nset (ssget "X"))
)
nset
)


(defun ss_endset (num / elast ess index) ;;; die letzten entities
;; (setq num(getint "\nEnter number of enties to select from end of
database: "))
(setq ess (ssadd))
(repeat num
(setq elast (entlast))
(if elast (progn (setq ess (ssadd elast ess)) (entdel elast)))
)
(setq index -1)
(repeat (sslength ess)
(entdel (ssname ess (setq index (1+ index))))
)
ess
)


;;; ss_s2e wandlet PICKSETs in OSETs um
(defun ss_s2e (sset / eset)
(if (= 'PICKSET (type sset))
(while (< 0 (sslength sset))
(setq eset (cons (cdr (assoc -1 (entget (ssname sset 0)))) eset)
sset (ssdel (ssname sset 0) sset)
)
)
)
eset
)

;;;ss_e2s wandelt Osets in PICKSETs um
(defun ss_e2s (eset / sset x)
(setq sset (ssadd))
(if (= 'LIST (type eset))
(mapcar '(lambda (x) (if (= 'ENAME (type x)) (setq sset (ssadd x sset))))
eset)
)
sset
)


(defun ss_block (name basepoint sset / e en blocktype)
(if (/= 'PICKSET (type sset)) (setq sset (ssadd)))
(if (or (/= 'STR (type name)) (= "" name)) (setq name "*A")) (if (= (substr
name 1 1) "*")
(setq blocktype 1 name "*A")
(setq blocktype 0)
)
(entmake (list
'(0 . "BLOCK")
(cons 2 name)
(cons 70 blocktype)
(cons 10 basepoint)
))
(ss_mapent
'(lambda (e)
(cond
((/= 1 (cdr (assoc 66 (entget e))))
(if (entget e) (progn
(entmake (entget e '("*")))
(entdel e)
))
)
((= 1 (cdr (assoc 66 (entget e))))
(if (entget e) (progn
(entmake (entget e '("*")))
(setq en e)
(while (/= "SEQEND" (cdr (assoc 0 (entget en))))
(setq en (entnext en))
(entmake (entget en '("*")))
)
(entdel e)
))
)
)
)
sset
)
(setq name (entmake '((0 . "ENDBLK"))))
(if name (progn
(entmake (append
'((0 . "INSERT"))
(list (cons 2 name))
(list (cons 10 basepoint))
))

))
(if name (entlast) nil)
)

(defun mycommand (cmnd / oldecho )
(setq oldecho (getvar "cmdecho"))
(setvar "cmdecho" 1)
(command cmnd)
(while (eq 1 (logand 1 (getvar "cmdactive")))
(command pause)
)
(setvar "cmdecho" oldecho)
)
Message 11 of 14
Anonymous
in reply to: Anonymous

I wrote (ss_mapent). Tom just renamed it from (mapent) to (ss_mapent)

"Luis Esquivel" wrote in message
news:42D8FAF62C8CE97882A994290CA397EB@in.WebX.maYIadrTaRb...
> Joshua Modglin
>
> Here are some very useful functions by
>
> Tom Berger
>
> ;;; START *******************************************************
>
> ;;; mapent is to selection sets what mapcar is to lists:
> (defun ss_mapent (function ss / i)
> (repeat (setq i (sslength ss))
> ((lambda (proc args / ss function i)
> (apply proc args)
> )
> function
> (list (ssname ss (setq i (1- i))))
> )
> )
> )
>
Message 12 of 14
Anonymous
in reply to: Anonymous

Here is the full thread I found for any clarification.


"Tony Tanzillo" wrote in message
news:613A08F9E0C4B33FA598C5F2124CFE18@in.WebX.maYIadrTaRb...
> I wrote (ss_mapent). Tom just renamed it from (mapent) to (ss_mapent)


>> Forum: comp.cad.autocad

>> Thread: Looking for LISP or ARX program(s) to manipulate selection
sets

>> Message 1 of 1




Subject: Re: Looking for LISP or ARX program(s) to manipulate selection
sets
Date: 12/13/1997
Author: Tom Berger


Save this thread


Randy,

here is my set of tools. Sometimes you´ll find comments in german language -
I created these functions for use in my own programs.

Tom Berger

;;; START *******************************************************

;;; mapent is to selection sets what mapcar is to lists:
(defun ss_mapent (function ss / i)
(repeat (setq i (sslength ss))
((lambda (proc args / ss function i)
(apply proc args)
)
function
(list (ssname ss (setq i (1- i))))
)
)
)

(defun ss_modent (ss dxf val / old)
(ss_mapent
'(lambda (ename)
(if (setq old (assoc dxf (entget ename)))
(entmod (subst (cons dxf val) old (entget ename)))
(entmod (cons (cons dxf val) (entget ename)))
)
)
ss
)
)


(defun ss_featurelist (ss dxf / res result)
(if (= 'PICKSET (type ss))
(ss_mapent
'(lambda (ename)
(if (setq res (cdr (assoc dxf (entget ename))))
(if (member res result)
nil
(setq result (cons res result))
)
)
)
ss
)
)
result
)


(defun ss_union (set1 set2 / set3) ;;;Vereinigung
(setq set3 (ssadd))
(if (and (= 'PICKSET (type set1)) (= 'PICKSET (type set2)))
(progn
(ss_mapent
'(lambda (x)
(setq set3 (ssadd x set3))
)
set1
)
(ss_mapent
'(lambda (x)
(setq set3 (ssadd x set3))
)
set2
)
)
)
set3
)


(defun ss_subtract (set1 set2 / set3) ;;;Differenz
(setq set3 (ssadd))
(if (and (= 'PICKSET (type set1)) (= 'PICKSET (type set2)))
(progn
(ss_mapent
'(lambda (x)
(setq set3 (ssadd x set3))
)
set1
)
(ss_mapent
'(lambda (x)
(if (ssmemb x set3)
(setq set3 (ssdel x set3))
)
)
set2
)
)
)
set3
)


(defun ss_intersect (set1 set2 / set3) ;; Schnittmenge
(setq set3 (ssadd))
(if (and (= 'PICKSET (type set1)) (= 'PICKSET (type set2)))
(ss_mapent
'(lambda (x)
(if (ssmemb x set2)
(setq set3 (ssadd x set3))
)
)
set1
)
)
set3
)


(defun ss_xor (set1 set2 / set3) ;;Vereinigung ohne Schnittmenge (setq set3
(ssadd))
(if (and (= 'PICKSET (type set1)) (= 'PICKSET (type set2)))
(progn
(ss_mapent
'(lambda (x)
(if (ssmemb x set2)
nil
(setq set3 (ssadd x set3))
)
)
set1
)
(ss_mapent
'(lambda (x)
(if (ssmemb x set1)
nil
(setq set3 (ssadd x set3))
)
)
set2
)
)
)
set3
)


(defun ss_newset (en / nset) ;; alle Entities, die seit EN erzeugt wurden.
Wenn EN = NIL, dann alle !
(setq nset (ssadd))
(if en
(while (setq en (entnext en))
(if (member (cdr (assoc 0 (entget en))) '("VERTEX" "SEQEND")) nil
(setq nset (ssadd en nset))
)
)
(setq nset (ssget "X"))
)
nset
)


(defun ss_endset (num / elast ess index) ;;; die letzten entities
;; (setq num(getint "\nEnter number of enties to select from end of
database: "))
(setq ess (ssadd))
(repeat num
(setq elast (entlast))
(if elast (progn (setq ess (ssadd elast ess)) (entdel elast)))
)
(setq index -1)
(repeat (sslength ess)
(entdel (ssname ess (setq index (1+ index))))
)
ess
)


;;; ss_s2e wandlet PICKSETs in OSETs um
(defun ss_s2e (sset / eset)
(if (= 'PICKSET (type sset))
(while (< 0 (sslength sset))
(setq eset (cons (cdr (assoc -1 (entget (ssname sset 0)))) eset)
sset (ssdel (ssname sset 0) sset)
)
)
)
eset
)

;;;ss_e2s wandelt Osets in PICKSETs um
(defun ss_e2s (eset / sset x)
(setq sset (ssadd))
(if (= 'LIST (type eset))
(mapcar '(lambda (x) (if (= 'ENAME (type x)) (setq sset (ssadd x sset))))
eset)
)
sset
)


(defun ss_block (name basepoint sset / e en blocktype)
(if (/= 'PICKSET (type sset)) (setq sset (ssadd)))
(if (or (/= 'STR (type name)) (= "" name)) (setq name "*A")) (if (= (substr
name 1 1) "*")
(setq blocktype 1 name "*A")
(setq blocktype 0)
)
(entmake (list
'(0 . "BLOCK")
(cons 2 name)
(cons 70 blocktype)
(cons 10 basepoint)
))
(ss_mapent
'(lambda (e)
(cond
((/= 1 (cdr (assoc 66 (entget e))))
(if (entget e) (progn
(entmake (entget e '("*")))
(entdel e)
))
)
((= 1 (cdr (assoc 66 (entget e))))
(if (entget e) (progn
(entmake (entget e '("*")))
(setq en e)
(while (/= "SEQEND" (cdr (assoc 0 (entget en))))
(setq en (entnext en))
(entmake (entget en '("*")))
)
(entdel e)
))
)
)
)
sset
)
(setq name (entmake '((0 . "ENDBLK"))))
(if name (progn
(entmake (append
'((0 . "INSERT"))
(list (cons 2 name))
(list (cons 10 basepoint))
))

))
(if name (entlast) nil)
)



(defun mycommand (cmnd / oldecho )
(setq oldecho (getvar "cmdecho"))
(setvar "cmdecho" 1)
(command cmnd)
(while (eq 1 (logand 1 (getvar "cmdactive")))
(command pause)
)
(setvar "cmdecho" oldecho)
)

;;; END *******************************************************

RVetter701 wrote:

> I'm looking for a program to perform the following selection set
> manipulations:
>
> Union of section sets
> difference of selection sets
> add selection sets
> substract selection sets
>
> please email me if you know of any such programs.
>
> Randy
Message 13 of 14
Anonymous
in reply to: Anonymous

Thanks for everyone's responses. It looks like I have some research ahead of me but now I have more than just the AutoCAD help to guide me. As regards the Selection Sets, I think I will stick to the good old way. I liked Cliff's suggestion but found that it echoed everything to the command line and did not see any speed difference. Thanks again, Joshua Modglin
Message 14 of 14
Anonymous
in reply to: Anonymous

My sample routine used vlax-dump-object only as an example using
vlax-map-collection. Mapping a ss collection using this function does not
necessarily echo to the screen. That may account for the slowness.
--
Cliff

"jmodglin" wrote in message
news:f0ff75a.11@WebX.maYIadrTaRb...
> Thanks for everyone's responses. It looks like I have some research ahead
of me but now I have more than just the AutoCAD help to guide me. As regards
the Selection Sets, I think I will stick to the good old way. I liked
Cliff's suggestion but found that it echoed everything to the command line
and did not see any speed difference. Thanks again, Joshua Modglin
>

Can't find what you're looking for? Ask the community or share your knowledge.

Post to forums  

Autodesk Design & Make Report

”Boost