Problem with vlax-curve-getDistAtPoint

 Hi
recently i found out that I have some problems with function vlax-curve-getDistAtPoint
it returns nil while it shouldnt

i checked it in autocad and it looks like it is bricscad problem

i attached sample file which contains one pline

paste into command line
[code](setq en (car(entsel)))[/code]
and pick pline
then paste
[code](vlax-curve-getDistAtPoint en (vlax-curve-getEndPoint en))[/code]
which returns nil instead of pline's length

anyone now why?

Comments

  • This is probably a tolerance issue. The coordinates of the end point are very big:
    [code]: id
    Select point to identify coordinates:
     X=6498939285.426  Y=5887766415.2297  Z=0[/code]

    To test this further:
    [code](- (vlax-curve-getParamAtPoint en (vlax-curve-getEndPoint en)) (vlax-curve-getendparam en)) => 1.04886e-008[/code]

    If you move the entity closer to the origin and try again you will find that the correct length is returned.

    As a workaround you can try this:
    [code](vlax-curve-getdistatparam en (vlax-curve-getendparam en))[/code]

    You should send in an SR.
  •  of course i use (vlax-curve-getdistatparam en (vlax-curve-getendparam en)) when i want to get length
    but problem with 
    (vlax-curve-getDistAtPoint en (vlax-curve-getEndPoint en))   
    exist also when point is in the middle of pline, then i can't use    
    (vlax-curve-getdistatparam en (vlax-curve-getendparam en)) 
    i cannot change coordinates of entity, is there any way to change tolerance, or use any other function which returns distance at point of pline?   
  • Please send us the drawing with the short description of the problem here, and we will be glad to investigate, to get a more stable behaviour.
    It helps us a lot to have the problem in our database, for reference, for our analysts + developers.

    Many thanks in advance !
  • @ Daniel:
    You can try something like the (Curve_GetDistAtPoint_Tolerance) function below.
    Apart from the end point your polyline has (at least) one more problematic point and that is the mid point of the 2nd segment.
    (Curve_GetDistAtPoint_Tolerance) works for both points but additional testing is no doubt required.

    [code](defun c:test ( / en pt)
      (setq en (car (entsel)))
      (setq pt (getpoint "\nPoint: "))
      (print (Curve_GetDistAtPoint_Tolerance en pt 1e-6))
      (princ)
    )

    (defun Curve_GetDistAtPoint_Tolerance (curve point MaxFuzz / fuzzVector halfFuzzVector)
      (setq fuzzVector (list MaxFuzz MaxFuzz MaxFuzz))
      (setq halfFuzzVector (list (/ MaxFuzz 2.0) (/ MaxFuzz 2.0) (/ MaxFuzz 2.0)))
      (cond
        ((vlax-curve-getdistatpoint curve point))
        ((vlax-curve-getdistatpoint curve (vlax-curve-getclosestpointto curve (mapcar '+ point halfFuzzVector))))
        ((vlax-curve-getdistatpoint curve (vlax-curve-getclosestpointto curve (mapcar '- point halfFuzzVector))))
        ((vlax-curve-getdistatpoint curve (vlax-curve-getclosestpointto curve (mapcar '+ point fuzzVector))))
        ((vlax-curve-getdistatpoint curve (vlax-curve-getclosestpointto curve (mapcar '- point fuzzVector))))
      )
    )[/code]
  • ... I should have said:
    (Curve_GetDistAtPoint_Tolerance), with a maxFuzz of 1e-6, works for both points but additional testing is no doubt required.
  • Improved version of (Curve_GetDistAtPoint_Tolerance):

    [code](defun Curve_GetDistAtPoint_Tolerance (curve point MaxFuzz / N_DistAtFuzzPoint fuzzVector halfFuzzVector)

      (defun N_DistAtFuzzPoint (fuzzPoint / dist)
        (if
          (and
            (setq fuzzPoint (vlax-curve-getclosestpointto curve fuzzPoint)) ; Project the fuzzPoint on the curve.
            (equal fuzzPoint point (* MaxFuzz 2.0))                         ; Make sure the projected fuzzPoint is reasonable close to the actual point.
            (setq dist (vlax-curve-getdistatpoint curve fuzzPoint))
          )
          dist
        )
      )

      (setq fuzzVector (list MaxFuzz MaxFuzz MaxFuzz))
      (setq halfFuzzVector (list (/ MaxFuzz 2.0) (/ MaxFuzz 2.0) (/ MaxFuzz 2.0)))
      (cond
        ((vlax-curve-getdistatpoint curve point))
        ((N_DistAtFuzzPoint (mapcar '+ point halfFuzzVector)))
        ((N_DistAtFuzzPoint (mapcar '- point halfFuzzVector)))
        ((N_DistAtFuzzPoint (mapcar '+ point fuzzVector)))
        ((N_DistAtFuzzPoint (mapcar '- point fuzzVector)))
      )
    )[/code]
  •  works fine if i use MaxFuzz higher then 1e-6
    if i try with 1e-7 or 1e-8 still return nil (at sample file) 
    why is that?
  • In a nutshell:
    In most computer programs real numbers are handled in a 64 bit binary floating point format. Translated to the decimal format this format results in 'only' ca. 16 significant figures. Your coordinates have 10 significant figures before the decimal point and therefore ca. 6 significant figures are left for the decimal portion. To make a reasonable change to these coordinates a tolerance of least 1e-6 or 0.000001 has to be used.
  •  ok
    understood 
    thank you for help, i will use this function for sure
  • Dear Roy, Dear Daniel,

    @Roy - perfect explanations :-) I was abotu to explain the same, but you were faster (as soooo often)

    @Daniel - I will process your support request next, and will keep you updated there;
    besides, as AutoCAD correctly works, it seems that our Lisp implementation for those (vlax-curve-xxx) functions
    should use a kind of dynamic tolerance, taking the dimensions of the curve into account;
    AutoCAD obviously does the same.

    Many greetings !
  • We have fixed that problem in BricsCAD Lisp now ... will be in one of upcoming BricsCAD versions;
    nevertheless, using Roy's code is the safest way when using real-world coordinates.

    Many greetings !
This discussion has been closed.