Mostrando postagens com marcador CogoPoint. Mostrar todas as postagens
Mostrando postagens com marcador CogoPoint. Mostrar todas as postagens

Programinha - Mover label de pontos em polilinhas

Bom dia!!!

Hoje vou postar um pequeno programa que me quebra um baita galho!!!

É o seguinte, em poligonais onde queremos mostrar os vértices numerados no civil 3d, normalmente usamos o comando CREATEPTPLYLNCTRVERTAUTO, que cria os pontos automaticamente nos vértices da polilinha.

Até aí tudo bem, veja como fica:
Percebe que a label do ponto fica por cima da linha?

Bem, dá pra criar um estilo que põe o texto mais pra fora, mas isso nem sempre fica bom. E você acaba "estrechando" manualmente a label. Mas e se tiver uns 200 pontos? Aí a coisa começa a ficar chata e você manda o desenhista fazer... hehehehe

Bom, é para isso que este programinha serve, veja:

Imports Autodesk.AutoCAD.Runtime
Imports Autodesk.AutoCAD.EditorInput
Imports Autodesk.AutoCAD.ApplicationServices
Imports Autodesk.AutoCAD.DatabaseServices
Imports Autodesk.AutoCAD.Geometry
Imports Autodesk.Civil.DatabaseServices

Public Class MovePtlabels
    'pra facilitar em muitos comandos:
    Public Function ED() As Editor
        Return DOC.Editor
    End Function

    'devolve o documento atual
    Public Function DOC() As Document
        Return Autodesk.AutoCAD.ApplicationServices.Application.DocumentManager.MdiActiveDocument
    End Function

    'move as labels dos pontos pela bissetriz das arestas
    <commandmethod commandflags.nopaperspace="" ovecogolabels="">
    Public Sub MoveCogoLabels()

        'selecione uma polilinha ou ecerra o comando:
        Dim peo As New PromptEntityOptions(vbNewLine & "Selecione a polilinha")
        peo.SetRejectMessage("Somente Polilinh")
        peo.AddAllowedClass(GetType(Polyline), True)
        Dim per As PromptEntityResult = ED.GetEntity(peo)
        If per.Status <> PromptStatus.OK Then Exit Sub

        'informe uma distância ou encerra o comando:
        Dim pdo As New PromptDistanceOptions(vbNewLine & "Indique a distância a afastar")
        Dim pdr As PromptDoubleResult = ED.GetDistance(pdo)
        If pdr.Status <> PromptStatus.OK Then Exit Sub

        'inicia a transação
        Using tr = DOC.TransactionManager.StartTransaction
            Try

                'obtem a polilinha selecionada
                Dim pl As Polyline = per.ObjectId.GetObject(OpenMode.ForRead)

                'determina se a polilinha está em sentido horário ou antihorário
                Dim s As Double = 0
                For i = 0 To pl.NumberOfVertices - 1
                    Dim pa = pl.GetPoint3dAt(i Mod pl.NumberOfVertices)
                    Dim pb = pl.GetPoint3dAt((i + 1) Mod pl.NumberOfVertices)
                    s += pa.X * pb.Y - pb.X * pa.Y
                Next

                'módulo do vetor entre a coordenada do vértice e a coordenada final da label
                'leva em conta o sentido da polilinha, para sempre mover para fora dela
                Dim f = If(s > 0, -1, 1) * pdr.Value

                'itera nos vértices:
                For i = 0 To pl.NumberOfVertices - 1
                    Dim pt As Point3d = pl.GetPoint3dAt(i)

                    'procura um cogopoint nas coordenadas deste vértice
                    'aqui podia criar uma query num pointgroup, mas fica como exercício
                    For Each cid In Autodesk.Civil.ApplicationServices.CivilApplication.ActiveDocument.CogoPoints
                        Dim cogo As CogoPoint = cid.GetObject(OpenMode.ForWrite)
                        If cogo.Location <> pt Then Continue For

                        'se encontrou um cogopoint, calcula a bissetriz das arestas do vértice
                        Dim pAntes As Point3d = pl.GetPoint3dAt(If(i = 0, pl.NumberOfVertices - 1, i - 1))
                        Dim pDepois As Point3d = pl.GetPoint3dAt((i + 1) Mod pl.NumberOfVertices)
                        Dim vAntes As Vector3d = pAntes.GetVectorTo(pt).GetPerpendicularVector
                        Dim vDepois As Vector3d = pt.GetVectorTo(pDepois).GetPerpendicularVector

                        'reseta a posição da label antes de reposicionar:
                        cogo.ResetLabel()

                        'move a label para a nova posição
                        cogo.LabelLocation = pt.Add(f * vAntes.Add(vDepois).GetNormal)

                    Next
                Next
                'aplica as alterações e faz regen
                tr.Commit()
                ED.Regen()
            Catch
                MsgBox(Err.Description)

            End Try
        End Using
    End Sub
End Class


Eu usei o Visual Studio 2010 para compilar a dll e compilei para a versão 2014, que deverá funcionar também no 2015 e 2016.

Agora, é carregar com o NETLOAD e usar, veja o resultado:

Percebe a diferença?

É isso!!!!

Fica com exercício criar um algorítimo mais eficiente para encontrar cogopoints nos vértices da polilinha.

Veja que o programa tem um controle de erros (try, catch) para evitar erros fatais.

Civil 3D - Ligar Cogo Points

Vamos voltar um pouco mais nas raízes deste blog, hehehe

Então, vamos escrever um programinha para resolver um pequeno problema:

Adicionar vértices em uma polilinha para que esta passe por Cogo Points do Civil 3D

Primeiro vamos ver como era a polilinha antes de processar:


Agora como ela ficará após processar:


Percebe a diferença?
Agora a polilinha passa pelos Cogo Points do Civil 3D

Utilidade disso???
Bem, imagine que você precise ligar os pontos de um eixo de estrada com 3 mil pontos...
Faz uma polilinha com muito menos que isso, passando pela "média" desses pontos e roda a lisp....
Seja criativo!!!!


Antes, vamos ver a receita do bolo:
  1. Pedir a seleção dos Cogo Points
  2. Pedir a seleção da polilinha
  3. Pedir uma distância de referência, para testar se o ponto é válido
  4. Em cada ponto, fazer:
    1. Obter a coordenada do cogo point
    2. Se a distância do ponto em relação à polilinha for maior que a distância pedida, pula pro próximo ponto
    3. Calcular a posição relativa do ponto na polilinha
    4. Armazenar esta posição e a coordenada do cogo point
  5. Ordenar os pontos da lista que foi obtida no looping acima
  6. Redefinir os vértices da polilinha, usando estes pontos
  7. Enfeitar o programinha
  8. Curtir o blog do neyton!!!!

Bem simples né?

Agora o código:

;|ADDVERTPL
  procura nos cogopoints selecionados os que poderão fazer parte da
  lista de vertices de uma polilinha 2d e adiciona vertices a esta pl
autor:
neyton luiz dalle molle
engenheiro civil
neyton@yahoo.com
https://tbn2.blogspot.com
licença de uso: free, mas mantenha os créditos.
|;


;liga as funções VL*
(vl-load-com)

;define uma nova função:
(DEFUN C:ADDVERTPL (/ SS PL LST ent vla pt pproj dist)
  ;controle de erros e undo e redo
  ;veja https://tbn2.blogspot.com para habilitar esta subrotina
  ;(tbn:error-init nil)

  

  ;pede a seleção de cogo points
  (SETQ SS (SSGET '((0 . "AECC_COGO_POINT"))))

  ;pede a seleção de uma polilinha 2d
  (SETQ PL (vlax-ename->vla-object (CAR (ENTSEL "\nSelecione a polilinha"))))

  ;pede a distancia de busca
  (setq dist (getdist "\nQual a distancia de busca <2>")
    dist (if dist dist 2))
  

  ;cria uma lista de coordenadas ((param (coordx cordy)) ...)
  (SETQ LST NIL)
  (
REPEAT (SSLENGTH SS)
  
    (
SETQ ;pega o primeiro ponto
          ENT (SSNAME SS 0)
      VLA (vlax-ename->vla-object ENT)

      ;calcula suas coordenadas
      PT  (LIST (vlax-get-property VLA "easting")
            (
vlax-get-property VLA "northing"))

      ;projeta o ponto na polilinha, usando p plano xy como referencia
      pproj   (VLAX-CURVE-GETCLOSESTPOINTTOPROJECTION PL PT '(0 0 1)))

    ;se a distancia do ponto projetado ao cogopoint for menor que uma distancia
    (IF    (< (DISTANCE PT pproj) dist)
      (
SETQ LST (CONS (LIST (VLAX-CURVE-GETPARAMATPOINT PL pproj)
                PT)
              LST)))

    ;passa pro proximo cogopoint
    (SSDEL ENT SS)
  )
 ;fim do repeat


  

  (SETQ ;ordena a lista
        LST (VL-SORT LST '(LAMBDA (A B) (< (CAR A) (CAR B))))

    ;monda uma lista de coordenadas '(x y x1 y1 x2 y2....)
    lst (APPLY 'APPEND (MAPCAr 'CADR lst))

    ;cria uma safearray da lista acima
    lst (VLAX-SAFEARRAY-FILL
          (VLAX-MAKE-SAFEARRAY
        VLAX-VBDOUBLE

        (CONS 0 (1- (LENGTH LST))))
          LST))
  ;faz a polilinha adotar as coordenadas colculadas
  (VLA-PUT-COORDINATES PL lst)

  ;reastaura o controle para o autocad
  ;(tbn:error-restore)
)

(
prompt
"ADDVERTPL carregado!!!
visite: https:\\\\tbn2net.com
"
)
(
princ)



Simples né?

Este programinha tem o intuito de mostrar como pode ser útil saber programar.... Imagine conectar os pontos "na mão"???

Curte aí!!!

Civil 3D - Visual Lisp - Converter blocos em cogopoints

Hoje vamos estudar um pouquinho de visual lisp no Civil 3D.

O problema:
Você recebeu um desenho de um escritório qualquer, que é a topografia de uma área.
Um dia o desenho foi do Civil 3D e tinha lá seus milhares de pontos de levantamento.
Como o cliente final quer AutoCAD puro, estes pontos foram explodidos.
Agora você quer restituir a triangulação com estes pontos por um motivo qualquer.
Existem pontos que não devem entrar no modelo, tais como fundo de PV ou coisa assim.
Então não dá para simplesmente usar "Drawing Objects" na nossa superfície.
Filtrar manualmente é inviável, pois são muitos pontos.

Solução 1:
Data Extraction, simples assim. O comando é DATAEXTRACTION
Considerações para esta solução:
Exploda mais uma vez os blocos e observe que os pontos se tornam, em geral, um MTEXT, que um dia foi a LABEL do COGOPOINT do Civil 3D e um POINT ou LINE, que representa a posição do ponto em si.
Note que o dataextraction será feito nestes MTEXT. A posição ficará levemente deslocada, pois o ponto de inserção do MTEXT não é necessariamente a coordenada do ponto. Bem, é só mover tudo depois.
Problema com esta solução:
Se algum ponto teve sua label "strechada" a posição ficará incorreta. O "Z" do MTEXT pode não ser o "Z" da coordenada do ponto, mas se estiver no conteúdo do MTEXT não é problema.

Solução 2:
Criar um "lispezinho", só de farra, hehehe
Analise um dos pontos. Qualquer um. Se explodimos ele, gera um POINT e um MTEXT, em geral. O bloco original está nas coordenadas exatas do cogopoint original. Só precisamos então obter o conteúdo do MTEXT e nele localizar a descrição e o nome do ponto. A cota pode ser descartada, uma vez que está na coordenada de inserção do bloco.
E como faríamos esta lisp?
Bem, primeiro, vamos pensar em como seria pra fazer "na raça", "na mão", "like a estagiário":


  1. Selecionar todos os pontos
  2. Obter a coordenada do ponto de inserção
  3. Em cada um deles, explodir
  4. Obter o MTEXT
  5. Ler o conteúdo do MTEXT
  6. Criar um cogo point do Civil 3D
  7. Definir seu nome e descrição com o valor que está no MTEXT
  8. Voltar em (2) até processar todos os pontos
  9. Fim
Simples, né?


Veja, e resumo é isso. Agora é só estudar "comofas" cada um dos passos acima dentro de um ambiente qualquer de programação. Escolhemos o LISP (por que será hein???)

No mais, é só enfeitar o código depois de pronto, colocando umas mensagens para o usuário e fornecendo um comando que ele possa chamar na linha de comando do Civil 3D.

O resultado final será esta lisp:


;|
blkx2cogo
lisp para converter blocos que foram cogopoints e foram explodidos
em cogopoints novamente
requisito: civil 3d 2007 a 2015
Autor: Neyton Luiz Dalle Molle
Engenheiro Civil
http://tbn2.blogspot.com
licença de uso: free, mas mantenha os créditos.
|;


;habilita as funções vla*
(vl-load-com)

;define um novo comando: blkx2cogo
(defun c:blkx2cogo (/ acadver civilver civilapp civildoc
          civilpts blks ss ent vla blkdef txt o lsttxt cogopoint
)

  ;controle de erros e undo e redo
  ;veja http://tbn2.blogspot.com/2006/10/avaliao-de-erros.html
  ;para habilitar esta subrotina
  ;(tbn:error-init nil)

  

  ;obtem algumas variaveis
  (setq
    ;qual a versão do autocad?
    acadver  (substr (vla-get-version (vlax-get-acad-object)) 1 4)
    

    ;qual a versão do civil 3d?
    civilver (cadr (assoc acadver
               '(("17.0" "4.0") ;2007
                 ("17.1" "5.0") ;2008
                 ("17.2" "6.0") ;2009
                 ("18.0" "7.0") ;2010
                 ("18.1" "8.0") ;2011
                 ("18.2" "9.0") ;2012
                 ("19.0" "10.0");2013
                 ("19.1" "10.3");2014
                 ("20.0" "11.0");2015, incluir outras
                 )))

    ;obtem o aplicativo Civil 3D
    civilapp  (vla-getinterfaceobject
        (vlax-get-acad-object)
        (
strcat "AeccXUiLand.AeccApplication."
            civilver))

    ;obtem o ducumento atual do Civil 3D
    civildoc  (vla-get-activedocument civilapp)

    ;obtem a coleção de pontos do documento atual do Civil 3D
    civilpts  (vlax-get-property civildoc "points")

    ;obtem a coleção de definições de blocos do autocad
    blks (vla-get-blocks (vla-get-activedocument (vlax-get-acad-object)))

    ;pede a seleção de blocos inseridos no desenho
    ss   (ssget '((0 . "INSERT")))
    )


  ;repita para cada bloco inserido que foi selecionado
  (repeat (sslength ss)
    ;obtenha a definição do bloco inserido
    (setq ent    (ssname ss 0)
      vla    (vlax-ename->vla-object ent)
      blkdef (vla-item blks (vla-get-name vla)))

    ;procura na definição, o MTEXT com o conteudo que queremos
    (vlax-for o blkdef
      (if (= "AcDbMText" (vla-get-ObjectName o))
    (
setq txt o)))

    (
setq
      ;desmonta o texto em uma lista
      ;"{\\C7;2137\\P7.45\\PP_A}" -> ("2137" 7.45 "P_A")
      lsttxt (read (vl-string-subst " \"" "\\P"
             (vl-string-subst "\" " "\\P"
               (vl-string-subst "\")" "}"
             (vl-string-subst "(\"" "{\\C7;"
              (vla-get-TextString txt))))))

      ;cria um cogopoint na mesma posição do bloco original
      cogopoint (vla-add civilpts (vla-get-insertionpoint vla)))

    ;redefine a descrição do cogopoint
    (vlax-put-property cogopoint "rawdescription" (caddr lsttxt))

    ;redefine o nome do cogopoint
    (vlax-put-property cogopoint "name" (car lsttxt))

    ;retira o bloco da seleção
    (ssdel ent ss)

    ;apaga o bloco antigo
    (entdel ent)

    ;mostra um contador decrescente no canto inferior esquerdo da tela
    (grtext -2 (itoa (sslength ss)))

    )
 ;fim do repeat

  ;reastaura o controle para o autocad
  ;(tbn:error-restore)
  

  ) ;fim do defun

;mensagem após o appload
(princ
"blkx2cogo carregado
Autor:neyton@yahoo.com
Use blkx2cogo para usar esta lisp"
)

;finaliza
(princ)



Abstraia o código e leia somente os comentários


Você verá que é a receita do bolo que escrevemos acima. No mais, procure na ajuda, como é a sintaxe das funções que usamos nesta lisp: defun, ssget, setq, repeat, grtext, funções que começam com VLA*,