Author Topic: height of lowest surface in 3dsolid?  (Read 8432 times)

0 Members and 1 Guest are viewing this topic.

Amsterdammed

  • Guest
height of lowest surface in 3dsolid?
« on: August 20, 2011, 12:04:32 PM »
Hello there,

I have some solids in my drawings that represent the ceiling of my technical equipment rooms and the beams supporting the ceiling. In an attempt to auto create shop drawings for my pipe support I want to be able to read out on each possible location in the drawing what the ceiling height is above. In other words I need to find out what height the lowest surface of the 3dsolid above is.
Any body any ideas?

Thanks Bernd

ElpanovEvgeniy

  • Water Moccasin
  • Posts: 1569
  • Moscow (Russia)
Re: height of lowest surface in 3dsolid?
« Reply #1 on: August 20, 2011, 12:46:46 PM »
Use any of the methods:
vla-Boolean
vla-GetBoundingBox
vla-IntersectWith
vla-SectionSolid
vla-SliceSolid

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: height of lowest surface in 3dsolid?
« Reply #2 on: August 20, 2011, 12:57:54 PM »
Code: [Select]
(defun c:T ( / oscmd boxe boxn EAboxn minpoint minpt maxpoint maxpt)
(setq oscmd (getvar "osmode"))
(setvar "osmode" 0)
(setq boxe (entsel "\nPick 3DSolid object to check its lowest hight in current UCS"))
(setq boxn (car boxe))
(setvar "osmode" 0)

(defun UCS2WCSMatrix ()
  (vlax-tmatrix
    (append
      (mapcar
'(lambda (vector origin)
   (append (trans vector 1 0 t) (list origin))
)
(list '(1 0 0) '(0 1 0) '(0 0 1))
(trans '(0 0 0) 0 1)
      )
      (list '(0 0 0 1))
    )
  )
)

(defun WCS2UCSMatrix ()
  (vlax-tmatrix
    (append
      (mapcar
'(lambda (vector origin)
   (append (trans vector 0 1 t) (list origin))
)
(list '(1 0 0) '(0 1 0) '(0 0 1))
(trans '(0 0 0) 1 0)
      )
      (list '(0 0 0 1))
    )
  )
)

(vl-load-com)
(setq EAboxn (vlax-ename->vla-object boxn))
  (vla-TransformBy EAboxn (UCS2WCSMatrix))
  (vla-getboundingbox EAboxn 'minpoint 'maxpoint)
  (vla-TransformBy EAboxn (WCS2UCSMatrix))
  (setq
   minpt (vlax-safearray->list minpoint)
   maxpt (vlax-safearray->list maxpoint)
  )
(prompt "\nLowest point hight of 3DSolid object in current UCS is : ") (princ (caddr minpt))
(setvar "osmode" oscmd)

(princ)
)

M.R.

EDIT : Sorry, I forgot to type (princ (caddr minpt)) instead of just (caddr minpt) - before modification...

Hope this now helps...
« Last Edit: August 21, 2011, 05:14:51 AM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

Amsterdammed

  • Guest
Re: height of lowest surface in 3dsolid?
« Reply #3 on: August 20, 2011, 05:54:34 PM »
Sorry MArko,

I get nil with your function

Bernd

Amsterdammed

  • Guest
Re: height of lowest surface in 3dsolid?
« Reply #4 on: August 20, 2011, 05:57:02 PM »
is there something like

vlax-curve-getClosestPointTo

for a solid? I mean what i really need i the shortest distance form a certain point to the solid

LE3

  • Guest
Re: height of lowest surface in 3dsolid?
« Reply #5 on: August 20, 2011, 06:12:33 PM »
is there something like

vlax-curve-getClosestPointTo

for a solid? I mean what i really need i the shortest distance form a certain point to the solid

Another limitation of lisp/vlisp - no (unless someone came up with a work-around)

You can do it with the BREP API - get all the faces of your solid and then in there use i.e: AcGePoint3d closestPoint = pSurface->closestPointTo(pointToTest); ... that's available in ARX or .NET flavors only

HTH.-

« Last Edit: August 20, 2011, 06:36:53 PM by DeVo »

LE3

  • Guest
Re: height of lowest surface in 3dsolid?
« Reply #6 on: August 20, 2011, 09:47:12 PM »
I mean what i really need i the shortest distance form a certain point to the solid

Ok, I need to practice my c++ and arx coding to much c#, so got the chance to write this function:

Code: [Select]
bool compare(std::pair<double, AcGePoint3d> pairOne, std::pair<double, AcGePoint3d> pairTwo)
{
return pairOne.first < pairTwo.first;
}

static void distClosestToSolidFace(void)
{
ads_name ss, ename;
TCHAR* promptPtrs[] = { _T("Select solid: "), _T("Remove solid: ") };
resbuf *ssfilter = acutBuildList(RTDXF0, _T("3DSOLID"), RTNONE);
AcGePoint3d pt;
if (acedGetPoint(NULL, _T("\nPoint to test: "), asDblArray(pt)) !=RTNORM) return;
if (acedSSGet(_T("_:S:$"), promptPtrs, NULL, ssfilter, ss) == RTNORM)
{
acutRelRb(ssfilter);
if (acedSSName(ss, 0, ename) != RTNORM) return;
acedSSFree(ss);
AcDbObjectId objid;
if (acdbGetObjectId(objid, ename) != Acad::eOk) return;
AcDbObjectPointer<AcDb3dSolid> pSolid(objid, AcDb::kForRead);
if (pSolid.openStatus() != Acad::eOk) return;
map<double, AcGePoint3d> pMap;
map<double, AcGePoint3d>::const_iterator it;
AcBrBrep brep;
brep.set(*(pSolid.object()));
AcBrBrepFaceTraverser acbrFaces;
for (acbrFaces.setBrep(brep); !acbrFaces.done(); acbrFaces.next())
{
AcBrFaceLoopTraverser acbrFaceLoop;
AcBrFace acbrFace;
acbrFaces.getFace(acbrFace);
for (acbrFaceLoop.setFace(acbrFace); !acbrFaceLoop.done(); acbrFaceLoop.next())
{
AcGeSurface* pSurface;
if (acbrFace.getSurface(pSurface) == AcBr::eOk)
{
AcGePoint3d pnt = pSurface->closestPointTo(pt);
delete pSurface;
double d = AcGeVector3d(pnt.asVector() - pt.asVector()).length();
pMap.insert(make_pair(d, pnt));
}
}
}
if (!pMap.empty())
{
std::pair<double, AcGePoint3d> minData = *min_element(pMap.begin(), pMap.end(), compare);
AcGePoint3d rpt = minData.second;
acutPrintf(_T("\nClosest distance: %.3f \n"), minData.first);
AcDbPoint *pPoint = NULL;
pPoint = new AcDbPoint(rpt);
AcDbBlockTableRecordPointer pBTR(acdbCurDwg()->currentSpaceId(), AcDb::kForWrite);
if (pPoint && (pBTR.openStatus() == Acad::eOk))
{
pBTR->appendAcDbEntity(pPoint);
pPoint->close();
}
pPoint = new AcDbPoint(pt);
if (pPoint && (pBTR.openStatus() == Acad::eOk))
{
pBTR->appendAcDbEntity(pPoint);
pPoint->close();
}
}
}
}

The above will return the minimum distance from any point selected to the 3d solid - and can be easily changed to be called as a function from autolisp as extension (like passing a vector of 3d solids for now it is just one and loop over them, etc.) - will leave that out since not that many want to download a binary file.

Quote
Command: test
Point to test:
Select solid:
Closest distance: 4.055

HTH.-
« Last Edit: August 20, 2011, 09:53:53 PM by DeVo »

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: height of lowest surface in 3dsolid?
« Reply #7 on: August 21, 2011, 05:16:43 AM »
I've modified code above, check it now...

M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

LE3

  • Guest
Re: height of lowest surface in 3dsolid?
« Reply #8 on: August 21, 2011, 12:08:18 PM »
I've modified code above, check it now...

M.R.

If you get a chance test the routine with the attached drawing save as 2010.

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: height of lowest surface in 3dsolid?
« Reply #9 on: August 21, 2011, 04:48:46 PM »
You didn't correctly setup your UCS, but nevertheless it is supposed to work with all possible UCS systems... Change UCS to WCS and test for yourself. It works fine on my comp...

M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

LE3

  • Guest
Re: height of lowest surface in 3dsolid?
« Reply #10 on: August 21, 2011, 04:54:41 PM »
You didn't correctly setup your UCS, but nevertheless it is supposed to work with all possible UCS systems... Change UCS to WCS and test for yourself. It works fine on my comp...

M.R.

I did that on purpose - I know what you just pointed above.

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: height of lowest surface in 3dsolid?
« Reply #11 on: August 22, 2011, 02:29:06 AM »
Well Devo, if you didn't know, routine measures distance from UCS origin point - '( 0 0 0 ) to lowest surface of object along axis parallel to relative UCS Z axis, so every time you want to check if surface is higher or lower it's good to know what distances are measured with your current UCS orientation and position...

M.R.
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

LE3

  • Guest
Re: height of lowest surface in 3dsolid?
« Reply #12 on: August 22, 2011, 12:17:52 PM »
Well Devo, if you didn't know, routine measures distance from UCS origin point - '( 0 0 0 ) to lowest surface of object along axis parallel to relative UCS Z axis, so every time you want to check if surface is higher or lower it's good to know what distances are measured with your current UCS orientation and position...

M.R.

If you read my post on Reply #5 - was trying to make my/a point - about alisp/vlisp - that's all.

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: height of lowest surface in 3dsolid?
« Reply #13 on: August 23, 2011, 06:49:12 AM »
Here, this should do it, but something is wrong... CAD doesn't find result of computation... Anyway, here is code, so if someone can fix it, go ahead and take all the thanks...

Code: [Select]
;; TRP
;; Transposes a matrix -Doug Wilson-
;;
;; Argument : a matrix

(defun trp (m) (apply 'mapcar (cons 'list m)))

;; MXV
;; Applies a transformation matrix to a vector -Vladimir Nesterovsky-
;;
;; Arguments : a matrix and a vector

(defun mxv (m v)
  (mapcar (function (lambda (r) (apply '+ (mapcar '* r v)))) m)
)

;; MXM
;; Multiplies (combinates) two matrices -Vladimir Nesterovsky-
;;
;; Arguments : two matrices

(defun mxm (m q)
  (mapcar (function (lambda (r) (mxv (trp q) r))) m)
)

(defun c:npt3DS nil (c:nearestpointto3DSolid))
(defun c:nearestpointto3DSolid ( / aobj adoc mspc pt radpt rad obj1 obj11 obj2 obj22 obj3 k matrix scf matrixn ptn radn )
  (vl-load-com)
  (setq aobj (vlax-get-acad-object)
        adoc (vla-get-activedocument aobj)
        mspc (vla-get-modelspace adoc)
  )
  (setq pt (getpoint "\nPick point from witch to calculate nearest point to 3DSolid")
        radpt (getpoint pt "\nPick point of radius of close sphere from witch to start calculation")
        rad (distance pt radpt)
  )
  (setq obj1
    (vla-addSphere mspc (vlax-3d-point pt) rad)
  )
  (defun dobj2 nil
    (if
      (not
        (vl-catch-all-error-p
          (vl-catch-all-apply 'vlax-ename->vla-object
            (list
              (setq obj2
                (car
                  (entsel "\nSelect 3DSolid for finding closest point to picked one at start")
                )
              )
            )
          )
        )
      )
      (setq obj2 (vlax-ename->vla-object obj2))
      (progn
        (prompt "\nWrong selection - nil selection - try once again")
        (dobj2)
      )
    )
  )
  (dobj2)
  (setq obj22 (vla-copy obj2))
  (setq k 0)
  (while
    (vl-catch-all-error-p
      (vl-catch-all-apply
'vla-Boolean
        (list obj1 acintersection obj2)
      )
    )
    (setq k (1+ k))
    (setq matrix
      (list
        (list 1.0001 0. 0. (car pt))
        (list 0. 1.0001 0. (cadr pt))
        (list 0. 0. 1.0001 (caddr pt))
        (list 0. 0. 0. 1.)
      )
    )
;    (if (= k 1) (setq matirixn matrix))
;    (setq matrixn (mxm matrix matrixn))
    (vla-transformby obj1
      (vlax-tmatrix matrix)
    )
    (vla-update obj1)
  )
  (setq scf (expt 1.0001 k))
  (setq matrixn
    (list
      (list scf 0. 0. (car pt))
      (list 0. scf 0. (cadr pt))
      (list 0. 0. scf (caddr pt))
      (list 0. 0. 0. 1.)
    )
  )
  (setq obj1
    (vla-addSphere mspc (vlax-3d-point pt) rad)
  )
  (setq obj11
    (vla-transformby obj1
      (vlax-tmatrix matrixn)
    )
  )
  (vla-copy obj22)
  (setq obj3
    (vla-update
      (vla-Boolean obj11 acintersection obj22)
    )
  )
  (setq ptn
    (vlax-safearray->list
      (vlax-variant-value
        (vla-get-Centroid obj3)
      )
    )
  )
  (prompt "\nNearest point on selected 3DSolid from point picked at start is : ")
  (princ ptn)
  (prompt "\nNearest distance to selected 3DSolid from point picked at start is : ")
  (princ
    (setq radn (distance pt ptn))
  )
  (vla-addSphere mspc (vlax-3d-point pt) radn)
(princ)
)
(prompt "\nShortcut to c:nearestpointto3DSolid is c:npt3DS")
(princ)

M.R.
« Last Edit: August 25, 2011, 05:56:21 PM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube

ribarm

  • Gator
  • Posts: 3225
  • Marko Ribar, architect
Re: height of lowest surface in 3dsolid?
« Reply #14 on: August 23, 2011, 09:07:43 AM »
Now it works... Without using matrices and transformations of objects... Only use of vl-cmdf commands :

Code: [Select]
(defun c:npt3DS nil (c:nearestpointto3DSolid))
(defun c:nearestpointto3DSolid ( / aobj adoc mspc pt radpt rad obj1 obj1e obj11 obj2 obj22 obj3 k scf ptn radn )
  (vl-load-com)
  (setq aobj (vlax-get-acad-object)
        adoc (vla-get-activedocument aobj)
        mspc (vla-get-modelspace adoc)
  )
  (setq pt (getpoint "\nPick point from witch to calculate nearest point to 3DSolid")
        radpt (getpoint pt "\nPick point of radius of close sphere from witch to start calculation")
        rad (distance pt radpt)
  )
  (setq obj1
    (vla-addSphere mspc (vlax-3d-point pt) rad)
  )
  (defun dobj2 nil
    (if
      (not
        (vl-catch-all-error-p
          (vl-catch-all-apply 'vlax-ename->vla-object
            (list
              (setq obj2
                (car
                  (entsel "\nSelect 3DSolid for finding closest point to picked one at start")
                )
              )
            )
          )
        )
      )
      (setq obj2 (vlax-ename->vla-object obj2))
      (progn
        (prompt "\nWrong selection - nil selection - try once again")
        (dobj2)
      )
    )
  )
  (dobj2)
  (setq obj22 (vla-copy obj2))
  (vla-copy obj22)
  (setq k 0)
  (while
    (vl-catch-all-error-p
      (vl-catch-all-apply
'vla-Boolean
        (list obj1 acintersection obj2)
      )
    )
    (setq k (1+ k))
    (setq obj1e (vlax-vla-object->ename obj1))
    (vl-cmdf "_.scale" obj1e "" pt 1.001)
  )
  (setq scf (expt 1.001 k))
  (setq obj1
    (vla-addSphere mspc (vlax-3d-point pt) rad)
  )
  (setq obj1e (vlax-vla-object->ename obj1))
  (vl-cmdf "_.scale" obj1e "" pt scf)
  (setq obj11 (vlax-ename->vla-object obj1e))
  (vl-cmdf "_.intersect" (vlax-vla-object->ename obj11) (vlax-vla-object->ename obj22) "")
  (setq obj3 (vlax-ename->vla-object (entlast)))
  (setq ptn
    (vlax-safearray->list
      (vlax-variant-value
        (vla-get-Centroid obj3)
      )
    )
  )
  (entdel (entlast))
  (prompt "\nNearest point on selected 3DSolid from point picked at start is : ")
  (princ ptn)
  (prompt "\nNearest distance to selected 3DSolid from point picked at start is : ")
  (princ
    (setq radn (distance pt ptn))
  )
  (vla-addSphere mspc (vlax-3d-point pt) radn)
(princ)
)
(prompt "\nShortcut to c:nearestpointto3DSolid is c:npt3DS")
(princ)

M.R. :lol:
« Last Edit: August 25, 2011, 05:59:00 PM by ribarm »
Marko Ribar, d.i.a. (graduated engineer of architecture)

:)

M.R. on Youtube