2

I have a simple algorithm that fails sometimes because it is comparing doubles. I look at a DXF drawing and get all the line segments, and also break it down into a series of points. When looping through all the points to identify if it forms a cycle (ie if a line touches, I should get 2 hits on a point) and inspecting the output they are close. So sometimes this algorithm and the equals with a delta comparison method gets a pass, then sometimes it fails...

So how close should a point be to consider it the same point or overlapping?

These should be the same, but then i think rounding happens and the numbers slightly adjust based on what I set the tolerance too making it sometimes equal and sometimes not..

Point: [4.6408, 14.8708] Point: [4.6799, 14.8156]

Even though it's a DXF file it doesn't seem to be exact or setup in a way to get identical values they are extremely approximate and fine grained, so I am not even sure how the DXF file itself works because when you use a drawing program you can make a distinct line entities that actually touch each other and the UI snaps the lines together...so should I compare it to one decimal place only? No decimal places?

I guess the issue is these drawings are made from a variety of different programs in a variety of different ways, maybe the DXF file format has something else I can inspect to identify this? For now I am doing it this way and it seems "buggy".

Any thoughts or suggestions? I do have a comparison / equals method that takes a tolerance, should I just make it really tight?

Thanks,

Panagiotis Kanavos
  • 120,703
  • 13
  • 188
  • 236
fr332lanc3
  • 151
  • 1
  • 11
  • What algorithm you are trying to implement? As usual it's easier to use existed library implementation instead trying to do it yourself, because working with real geometry data it's so hard and unpredictable. You can try different epsilon values to compare, but it's dead end path, everytime you can find data with which your values don't work. I know c++ boost geometry is really good, I don't know about c# exactly but I heard there is open source projects of geometry library. – Lana Jan 10 '21 at 20:09
  • 3
    The epsilon you use will/should be a function of the scale of the drawing. You need to decide how close two points need to be and a particular drawing, before they are the same – Flydog57 Jan 10 '21 at 20:32
  • I usually do a BBOX of the stuff and then set the delta to some percentage of the bbox size like `size/1000000` ... if your output is grainy it might suggest either the export to dxf was not OK (some fileformats use integers like WMF,EMF,DKR,DK3,...) and or you lose accuracy on your side somwhere. Do you have a sample dxf file (and its preview showing the problem) so we can see if it is the file or your code? – Spektre Jan 11 '21 at 08:15
  • There is no single answer to this, because “a variety of different programs in a variety of different ways” can produce final errors of any magnitude. Various uses of floating-point arithmetic can magnify initial errors into any amount, including infinity and NaN. You have to know something about the programs and ways in order to determine a bound on how much error they can produce and therefore how much error you need to tolerate. (You also should determine a bound on how much error you can tolerate, and you must hope the former is less than the latter.) – Eric Postpischil Jan 11 '21 at 12:41
  • Is this an algorithm that just needs to look good on the display? Then perhaps you can consider points as the same if they map to the same pixel. – Eric Postpischil Jan 11 '21 at 12:43
  • This is all great and useful information. I assumed DXF drawings data the points would be stored and identical because the user connected two line segments using the UI for example which doesn't seem to be the case? I have tried a few programs and they seem to snap to each other and connect, using two lines it generates two entities with points (not using a single polyline which would be better) but we can't control how we get drawings. The idea is we have to do an "open contour / is closed" analysis on the dxf drawing, for nesting and laser cutting. – fr332lanc3 Jan 11 '21 at 23:40
  • `public static bool Equals(double d1, double d2, double tolerance=0.000001) { double a = Math.Abs(d1 - d2); if (a <= tolerance) return true; return false; }` – fr332lanc3 Jan 11 '21 at 23:41
  • In my experience it is not safe to try and compare double with double. Invariabke there is rounding precision issues after several decimal places making them different. I have always handled this issue by rounding my double values to 3 or 4 decimal places. By having consistent precision you can safely do comparisons. – Andrew Truckle Jan 16 '21 at 22:06
  • So round to 4 and always round up for example and compare? – fr332lanc3 Jan 17 '21 at 23:49
  • @fr332lanc3 In my experience this does help for comparing coordinate values. – Andrew Truckle Jan 19 '21 at 08:31

1 Answers1

0

I know this is VBA but I just wanted to convey the principles involved:

Private Function ComparePoints(ptPoint() As Double, ptVariant As Variant, Optional ByVal dElevation As Double = 0#) As Boolean
    ComparePoints = False
    
    If (UBound(ptVariant) = 1) Then
        If (ptPoint(0) = Round(ptVariant(0), 3) And _
            ptPoint(1) = Round(ptVariant(1), 3) And _
            ptPoint(2) = Round(dElevation, 3)) Then
           ComparePoints = True
        End If
    Else
        If (ptPoint(0) = Round(ptVariant(0), 3) _
             And ptPoint(1) = Round(ptVariant(1), 3) _
             And ptPoint(2) = Round(ptVariant(2), 3)) Then
           ComparePoints = True
        End If
    End If
End Function

Public Function Round(ByVal dValue As Double, ByVal iPrec As Integer) As Double
    Dim strText As String
    Dim strNumber As String
    Dim strFormatString As String
    
    If (iPrec <= 0) Then
        strFormatString = "0"
    Else
        strFormatString = "0." & String$(iPrec, "0")
    End If
    
    strText = CStr(dValue)
    strNumber = Format$(strText, strFormatString)

    Round = CDbl(strNumber)
End Function

Code would be a bit different for C#. In the above ComparePoints is designed for testing:

  • a 3D coordinate against another 3D coordinate
  • a 3D coordinate against a 2D coordinate (with elevation).

The latter applies when using LWPOLYLINE elements.

Note that the above assumes all coordinates are in the World Coordinate System for the comparisons to work. Transformation of coordinates is another issue.

Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
  • 1
    Thanks, I think the problem is also further complicated because I am using a multi threaded approach. Now that I've improved the comparison / tolerance checks and use a "is a cycle" type true/false it seems much more reliable after finding a good tolerance. Now the problem seems to be a multi threaded approach to do several shapes at the same time it's less reliable, which makes me think the problem is now somewhere else (a new problem) so one step forward and one step back I guess. – fr332lanc3 Feb 06 '21 at 18:27