Reposition block refs onto a TIN with python


import traceback
from pyrx_imp import Rx
from pyrx_imp import Ge
from pyrx_imp import Gi
from pyrx_imp import Gs
from pyrx_imp import Db
from pyrx_imp import Ap
from pyrx_imp import Ed
from pyrx_imp import Cv

# debug
def PyRxCmd_pydebug() -> None:
import PyRxDebug
PyRxDebug.startListener()

def PyRxCmd_doit() -> None:
try:
esel = Ed.Editor.entSel("\nSelect TIN Surface: ", Cv.CvDbTinSurface.desc())
if esel[0] != Ed.PromptStatus.eOk:
print("Oops {}: ".format(esel[0]))
return

filter = [(0, "INSERT"), (2, "Simple Tree")]
ssres = Ed.Editor.selectAll(filter)
if ssres[0] != Ed.PromptStatus.eOk:
print("Oops {}: ".format(ssres[0]))
return

pSurface = Cv.CvDbTinSurface(esel[1])
intersectTarget = Db.Line()

for id in ssres[1].objectIds():
ref = Db.BlockReference(id, Db.OpenMode.kForWrite)
sp = ref.position()
ep = sp + Ge.Vector3d.kZAxis * pSurface.maxElevation()
intersectTarget.setStartPoint(sp)
intersectTarget.setEndPoint(ep)
pnts = pSurface.intersectWith(intersectTarget,Db.Intersect.kExtendArg)

if len(pnts):
ref.setPosition(pnts[0])

except Exception as err:
traceback.print_exception(err)
before:

After:


Comments

  • Need later Versions of Bricscad say V21 + Pro version, else its a proxy object, which are hard to deal with.

  • Ah, good point, BRX/Python wrappers are compiled for V24 Pro onwards. I have no intention of making back builds.
    However, it’s open source, it probably wouldn’t be hard to make back builds if you know your way around a compiler
  • This is an alternative using the LISP TinSurface + Civil functionality, the tin:elevationatpoint function thus avoiding to create a virtual intersection line, although alternatively this is possible by using the tin:getintersectionswithline function !
    In the following code, you find both, the latter deactivated ;;;;;
    I have tested the code with V24 pro without any problems, but in V22pro + V23 pro both mentioned functions do not return the necessary value, simply they not work..??? I don't know why ...
    Here is the code
    ----------------------------------------------------------------------------------------------------------------------------------
    (vl-load-tin)
    (defun c:popTin (/ ssTin ssObj idx obj insPt)

    ;select a tin surface
    (setq ssTin (car (entsel "Select a TIN surface : /n")))
    (prompt "Select the objects to populate the TIN surface : /n")
    (setq ssObj (ssget)
    idx 0)

    (while (< idx (sslength ssObj))
    (vl-cmdf "_MOVE" (setq obj (ssname ssObj idx)) ""
    (setq insPt (cdr (assoc 10 (entget obj)))) ;from point

    ; get the elevation of the insertion point on the TIN surface
    (list (car insPt)(cadr insPt)(tin:elevationatpoint ssTin insPt)) ;to TIN Elevation

    ; alternatively find the elevation using an intersection of a virtual line
    ; connecting the object insertion point and the point having the max tin elevation ...

    ;(tin:getintersectionswithline ssTin insPt (list (car insPt)(cadr insPt)(tin:getmaxelevation ssTin NIL)) NIL NIL) ;to TIN Elevation

    );r
    ; get next object
    (setq idx (1+ idx))
    );w

    )
    ------------------------------------------------------------------------------------------------------------------------------

    You find attach a dwg to test


  • Its_Alive
    edited March 14
    Well done!
    I knew there were some lisp wrappers for tins, but not to what extent. Cool!
    I can’t say why it doesn’t work on older versions, buy your routine works great on V24
  • Bricscad V20 has no TIN:ELEVATIONATPOINT I think the Tins were introduced in V21.
  • Sakko
    edited March 21
    I have mentioned above that the lisp routine does not function in V22pro + V23 pro, but this not true and the reason is a trivial one. I have simply used a TIN surface created in V24 which turns to a Proxy object in V22 and V23, due to backward incompatibility of the underlying programming API (brx)!
    So everything works ok if the TIN surface is created in the lower version e.g. V22 and then is used in a higher version V23, V24 and so forth....
    ...
    ALANH
    As for the V20, there is a method of the TIN surface object tinSurface.Drape(points) .
    The drape function projects a polyline (lwpolyline) to a 3dpolyline onto the given TIN Surface.
    There is an example in the API dir C:\Program Files\Bricsys\BricsCAD V20 en_US\API\dotNet\CsBrxMgdCivil of the installation dir of V20, in the TinSurfaceSample.cs file to study...
    I have modified this a little bit and created the command TINDRAPEPOLY , which creates/projects a 3dpolyline onto the TIN surface, for any polyline lying partially within the TIN surface boundary (footprint).
    The following lisp file creates a lisp function and command tin:elevationatpointV20 and POPTIN respectively, which enable us to populate the TIN surface with the trees in V20 like in the lisp civil api in V21,V22,V23,V24.....
    Here is the lisp code:
    -------------------------------------------------------------------------------------------------------------------------------------------
    (defun c:popTin (/ ssTin ssObj idx obj insPt)

    ;select a tin surface
    (setq ssTin (car (entsel "Select a TIN surface : /n")))
    (prompt "Select the objects to populate the TIN surface : /n")
    (setq ssObj (ssget)
    idx 0)

    (while (< idx (sslength ssObj))
    (vl-cmdf "_MOVE" (setq obj (ssname ssObj idx)) ""
    (setq insPt (cdr (assoc 10 (entget obj)))) ;from point

    ; get the elevation of the insertion point on the TIN surface
    (list (car insPt)(cadr insPt)(tin:elevationatpointV20 ssTin insPt nil nil)) ;to TIN Elevation
    )
    ; get next object
    (setq idx (1+ idx))
    );w

    )
    ;-------------------------------------- tin:elevationatpointV20 --------------------------------------------------------------
    ;;; call (tin:elevationatpointV20 (car(entsel)) (getpoint) nil nil)

    (defun tin:elevationatpointV20 (tinSurf point3d flag1 flag2 / bounds pl dpl vlin elevAtP)

    ; get the lower-left and top-right points of the TIN surface
    (setq bounds (vbbox tinsurf))
    ; draw a horizontal polyline in XY direction throught the point3D bounded by bounds
    (vl-cmdf "._PLINE" (list (nth 0 point3d )(nth 1 (nth 0 bounds)) (nth 2 point3d ))
    (list (nth 0 point3d )(nth 1 (nth 1 bounds)) (nth 2 point3d ))
    ""
    )
    (setq pl (entlast))
    ;drape the polyline on the TIN surface
    (vl-cmdf "_TINDRAPEPOLY" tinSurf pl)
    (setq dpl (entlast))
    ;draw a vertical line through point3d bounded by bounds
    (vl-cmdf "._LINE" (list (nth 0 point3d )(nth 1 point3d )(nth 2 (nth 0 bounds)))
    (list (nth 0 point3d )(nth 1 point3d )(nth 2 (nth 1 bounds)))
    ""
    )
    (setq vlin (entlast))
    ; return the intersection point of the vertical line with the draped 3d polyline...
    (setq elevAtP (vlax-safearray->list (vlax-variant-value
    (vla-IntersectWith (vlax-ename->vla-object vlin) (vlax-ename->vla-object dpl) acExtendThisEntity)))
    )
    (if (= flag1 nil)
    (progn
    (entdel dpl)
    )
    )
    (if (= flag2 nil)
    (progn
    (entdel pl)
    (entdel vlin)
    )
    )
    (nth 2 elevAtP)
    )

    ;-----------------------------------------vbbox --------------------------------------------------------------------

    ;;;;;;returns bounding box as 2 points
    (defun vbbox ( objid / minb maxb)

    (if (= (type objid) 'ENAME) ; if ENAME is passed convert to VLAobject
    (setq objid (vlax-ename->vla-object objid))
    )
    (vla-GetBoundingBox objid 'minb 'maxb)
    (setq minb (vlax-safearray->list minb)
    maxb (vlax-safearray->list maxb)
    )
    (list minb maxb)
    )

    ------------------------------------------------------------------------------------------------------------------------------------

    The function has 2 flags to selectively keep the draped 3dpolylines (dpl) and linework (pl,vlin) or delete them ....
    The assembly TinDrapePolyV20.dll implements the TINDRAPEPOLY command and must be loaded using the NETLOAD command, before the POPTIN and tin:elevationatpointV20 can be used!
    For those interested in the c# implementation, the c# project is attached...
    You can also try the TINDRAPEPOLY command with any polyline lying partially or wholy within the tin surface footprint...
    You find attached the V20 DWG file, the c# project file and the compiled dll to netload...








  • You find the compiled assembly file TinDrapePolyV20.dll in the \TinDrapePoly\bin\Debug\ directory of the uploaded project file, here attached again
  • Sakko
    edited March 20
    For users the fastest and simplest way to accomplish tasks similar to the one described in this thread, is to use the command TINPROJECT.....all trees are moved to position in one simple step !
    The command exists since V21...