• This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Leggi altro.

Aggiungi valore in attributo blocco

Cristallo

Utente Standard
Professione: Leggo e confronto
Software: Lettura critica
Regione: Fuori dalla cerchia
#1
Allora, mi è partito l'embolo e vorrei scrivere una routine che selezionati una serie di blocchi (che contengono una quota altimetrica sotto forma di valore di un attributo) possa aggiungere/sottrarre un delta specifico.
L'idea è semplice, una sorta di AddVal già presente sul sito, ma che agisca sui valori degli attributi.

Ma mi sono scontrato con Acad gia al primo step, e cioè ottenere il valore dell'attributo contenuto nel blocco.
Ottengo la lista blocco, ne cercho le sotto entità, le scorro tutte (tutto questo a linea di comando quindi se presente vedo ciò che sto cercando), ma in nessuna riesco a trovare un gruppo che contenga l'attuale valore dell'attributo.

Qualcuno mi da una dritta?
 

GP.

Utente Senior
Professione: Nientologo
Software: uozapp
Regione: Vercelli
#2
Inserisci il nome del blocco e il nome dell'etichetta nelle variabili all'inizio.

Codice:
(defun c:cambiaquota ( / NB NE blk n BL listATT attVAL)
    
    (setq NB "QUOTA") ;nome blocco
    (setq NE "ALTIM") ;nome etichetta

    (vla-startundomark (vla-get-activedocument (vlax-get-acad-object)))
    (if (and
            (princ "\nSelezionare i Blocchi da modificare ")
            (setq blk (ssget (list '(0 . "INSERT") (cons 2 NB))))
            (setq delta (cond
                            ( (getdist (strcat "\nDelta QUOTA" (if delta (strcat " <" (rtos delta 2 2) ">: ")": "))) )
                            ( delta )
            )           )
        )
        (repeat (setq n (sslength blk))
            (setq BL (ssname blk (setq n (1- n))))
            (foreach listATT (vlax-invoke (vlax-ename->vla-object BL) 'getattributes)
                (if (= (strcase (vla-get-tagstring listATT)) NE)
                    (progn
                        (setq attVAL (+ (atof (vla-get-textstring listATT)) delta))
                        (vla-put-textstring listATT (rtos attVAL 2 (getvar 'luprec)))
                    )
                )
            )
        )
    )
    (vla-endundomark (vla-get-activedocument (vlax-get-acad-object)))
    (princ)
)
 

Cristallo

Utente Standard
Professione: Leggo e confronto
Software: Lettura critica
Regione: Fuori dalla cerchia
#3
E che ne parliamo a fare? Qui posso solo ringraziarti.
Ovviamente il tuo codice fa esattamente quello che cercavo, adesso mi devo solo applicare un po per affinarlo.
Grazie ancora.
 

GP.

Utente Senior
Professione: Nientologo
Software: uozapp
Regione: Vercelli
#4
Prego :smile:

Se preferisci in vanilla il loop sui singoli blocchi si potrebbe impostare così:

Codice:
        (repeat (setq n (sslength blk))
            (setq BL (ssname blk (setq n (1- n))))
            (if (setq ent1 (entnext (cdr (car (entget BL)))))
                (while (= (cdr (assoc 0 (entget ent1))) "ATTRIB")
                    (if (= (strcase (cdr (assoc 2 (entget ent1)))) NE)
                        (progn
                            (setq attVAL (cdr (assoc 1 (entget ent1))))
                            (setq NewAttVAL (rtos (+ (atof attVAL) delta) 2 (getvar 'luprec)))
                            (entmod (subst (cons 1 NewAttVAL) (assoc 1 (entget ent1)) (entget ent1)))
                        )
                    )
                    (setq ent1 (entnext ent1))
                )
            )
        )
 

GP.

Utente Senior
Professione: Nientologo
Software: uozapp
Regione: Vercelli
#5
Altra cosa, se non vuoi limitare il lisp ad un solo NOMEBLOCCO, puoi selezionarli con un filtro sul DXF 66

(ssget "X" '((0 . "INSERT") (66 . 1)))

Se il valore è 1 l'entità INSERT è seguita da una serie di entità ATTRIB, che terminano con un'entità SEQEND.
:smile:
 

Cristallo

Utente Standard
Professione: Leggo e confronto
Software: Lettura critica
Regione: Fuori dalla cerchia
#7
Allora...
ho preso il nome blocco (poco flessibile doverlo indicare nel listato) mediante una semplice associazione al gruppo 2
(setq NB (cdr (assoc '2 (entget (car (entsel "Selezionare uno dei blocchi da aggiornare: "))))))

Adesso, se volessi ottenere il tag dell'unico attributo presente nel blocco?
Maledetti attributi, si nascondo ben bene!
 

GP.

Utente Senior
Professione: Nientologo
Software: uozapp
Regione: Vercelli
#8
Se il blocco ha attributi questo frammento ti restituisce il nome dell'etichetta e il valore del primo attributo.

(setq BL (car (entsel "Selezionare uno dei blocchi da aggiornare: ")))
(setq ent1 (entget (entnext (cdr (car (entget BL))))))
(setq etichetta (cdr (assoc 2 ent1)))
(setq valore (cdr (assoc 1 ent1)))
 

Cristallo

Utente Standard
Professione: Leggo e confronto
Software: Lettura critica
Regione: Fuori dalla cerchia
#9
Sempre sul pezzo. Funziona alla grande ed il fatto che lo hai splittato in più passaggi mi consente di ragionare su un'altro aspetto, e cioè che se il valore dell'attributo ha altri caratteri oltre il numeretto della quota posso stralciarli prima e ricostruirli dopo (una cosa del tipo "-5.70 q.p.f.") o addirittura scegliere di saltare quell'entità.

Giusto per cultura mia, se ripeto l'entnext, passo all'attributo successivo, fino ad incontrare un SEQUEND?
 

Cristallo

Utente Standard
Professione: Leggo e confronto
Software: Lettura critica
Regione: Fuori dalla cerchia
#12
Allora...
partendo dal "la" di GP ho sistemato un pò il listato ed ora il lisp aggiunge/sottrae un delta da un blocco con singolo attributo, conservandone un eventuale testo seguente la quota.
Ad esempio due blocchi contenenti "3.50" e "-3.50 estradosso", aggiungendo un delta di 0.30 risulteranno "3.80" e "-3.20 estradosso".
La selezione dei blocchi su cui operare avviene mediante pick del blocco (è il lisp ad ottenere il nome blocco ed il tag dell'attributo) e successivamente sulla selezione dei blocchi da modificare (il lisp seleziona solo quelli soddisfcenti i requisiti del pick precedente).

Fin qui tutto bene, ora le note dolenti.

Nella versione 3 tutto funziona bene, ma se si seleziona un blocco dinamico il risultato del nome blocco sarà *Uetc (i blocchi dinamici si presentano così) ed ovviamente non ci sarà selezione a cui applicare il delta.
Nella versione 4 ho risolto, aggiungendo il recupero dell'effective name del blocco anonimo, ma quando vado a selezionare con ssget non c'e' un blocco che rispetti la condizione ssget: e per forza! io seleziono magari un blocco di nome "Planiquo", il lisp trova una marea di blocchi di nome "*Uetc"
Come gli faccio selezionare un blocco dinamico, ma che rispetti le condizioni del blocco dinamico scelto con il pick?

Non fate caso al fatto che le variabili restano piene dopo l'esecuzione del lisp, essendo in fase embrionale l'ho lasciato così per avere sottomano il valore delle variabili al momento del crash.
 

Allegati

GP.

Utente Senior
Professione: Nientologo
Software: uozapp
Regione: Vercelli
#13
Codice:
;cattura tutti i blocchi
(setq blk1 (ssget "_X" '((0 . "INSERT"))))

;inizializza il gruppo di selezione blk
(setq blk (ssadd))

;loop su tutti i blocchi: se il nome effettivo corrisponde a quello voluto (NB) aggiunge il blocco a blk
(repeat (setq n (sslength blk1))
    (if (= NB (vlax-get-property (vlax-ename->vla-object (setq b (ssname blk1 (setq n (1- n))))) 'EffectiveName))
        (setq blk (ssadd b blk))
    )
)
 

Cristallo

Utente Standard
Professione: Leggo e confronto
Software: Lettura critica
Regione: Fuori dalla cerchia
#14
Soluzione intelligentemente semplice ad un problema apparentemente insormontabile.
Ovviamente funziona, anche se pare che ho avuto qualche problemino passando dagli anonimi ai normali, ma lo affinerò.
 

Cristallo

Utente Standard
Professione: Leggo e confronto
Software: Lettura critica
Regione: Fuori dalla cerchia
#16
Con 'EffectiveName dovrebbe essere ininfluente il tipo di blocco.
Si lo pensavo anche io. Ma al secondo ciclo (con altro blocco) la selezione BLK1 restava vuoto nonostante NB (nome blocco) fosse corretto.
Ho pensato che fosse una questione di svuotamento di qualche variabile (che in fase bozza non vengono resettate), ma non ho potuto approfondire per tempo.

Visto che ci sei, ti pongo un nuovo quesito. Ammettiamo che il valore dell'attributo non inizi per un numero, ma vi sia una stringa iniziale, tipo "Quota 11.23" e diciamo che lo assegno alla var. VALORE.
In questo caso tutto il lisp va in crisi.
Ho provato ad isolare la sola parte iniziale mediante (read VALORE) e correttamente mi restituisce QUOTA, ma se cerco di sostituirlo nella stringa (setq VALORE2 (subst "" (read VALORE) VALORE)) mi restituisce errore.
Indagando il risultato di read lo vede come SYM e non come stringa, quindi il subst non va.
C'e' modo di cambiare la tipologia di dato che legge READ?
 

GP.

Utente Senior
Professione: Nientologo
Software: uozapp
Regione: Vercelli
#17
Partendo da
(setq VALORE "Quota 11.23")

;imposto a 0 il contatore dei caratteri della stringa
(setq n 0)

;scorre tutti i caratteri fino a quando trova un numero (*), il valore di n si blocca quindi sul numero che corrisponde alla posizione nella stringa
(while (not (<= 48 (ascii (substr VALORE (setq n (1+ n)) 1)) 57)))

(setq v1 (substr VALORE 1 (1- n))) -> restituisce "Quota "

(setq V2 (substr VALORE n (strlen VALORE))) -> restituisce "11.23"


Modifichi il valore di v2 e poi con
(setq VALORE (strcat v1 v2)) ripristini la stringa dell'attributo.


(*) I caratteri ASCII da 48 a 57 sono numeri.
 

Cristallo

Utente Standard
Professione: Leggo e confronto
Software: Lettura critica
Regione: Fuori dalla cerchia
#18
Guazie delle spiegazioni. Avevo immaginato che dall'alto dei tuoi magheggi ci fosse una via più semplice, invece bisogna scorrere tutta la stringa carattere per carattere.
Ma va bene così.