mozman / ezdxf

Python interface to DXF
https://ezdxf.mozman.at
MIT License
937 stars 191 forks source link

Start and end angles from bulge_to_arc have "unexpected values" #1180

Closed TinyTrouble closed 1 month ago

TinyTrouble commented 1 month ago

The problem with start and end angles has already been noted in issue #943, but it was treated with an "all your fault" reply and closed

There are two separate issues but they are so simple to deal with that I will describe them together.

1) If the bulge is negative, the the start and end points are swapped breaking the polyline, as the requirement that the end point of one segment is the same as the start of the next is violated

2) The function can return subtended arcs of greater than 2 pi.

The user was advised to "normalize" the results - I would say "correct"

    if bulge < 0.0:
        t = start
        start = end
        end = t

    if abs(bulge) < 1.0:
        if abs(end-start) > math.pi:
            if start < end:
                start += math.pi * 2.0
            else:
                end += math.pi * 2.0
    else:
        if abs(end-start) < math.pi:
            if start < end:
                end += math.pi * 2.0
            else:
                start += math.pi * 2.0

This is actually longer than the code to calculate consistent results.

The first problem comes from lifting code from a different context The function bulge_to_arc ends with code to SWAP the START and END points!

  if bulge < 0:
      return c, angle(c, end_point), angle(c, start_point), abs(r)
  else:
      return c, angle(c, start_point), angle(c, end_point), abs(r)

which comes from Lee Mac's

  (if (minusp b)
      (list c (angle c p2) (angle c p1) (abs r))
      (list c (angle c p1) (angle c p2) (abs r))
  )

which is not appropriate for polylines where successive segments must be contiguous and it also violates the function definition.

The second issue is the ambiguous recalculation of the angles at the end. The start angle has already been calculated to find the centre form the start point, and the end angle is just the start angle plus theta - there is no need to use the ambiguous angle function, Since theta is always less than 2 pi this cannot give subtended angles > 2 pi

My rewrite is

    my_chord2 = math.dist((x,y),(next_x, next_y)) / 2.0
    my_sagitta = bulge * my_chord2
    my_radius = ((my_chord2 * my_chord2 + my_sagitta * my_sagitta) / (2.0 * my_sagitta))
    my_subtended = 4.0 * math.atan(bulge)
    my_other_angles = (math.pi - my_subtended) / 2.0
    my_chord_angle = (Vec2(next_x, next_y) - Vec2(x, y)).angle
    my_angle1 = my_chord_angle + my_other_angles
    my_center = Vec2(x ,y) + Vec2.from_angle(my_angle1, my_radius)
    my_start = my_angle1
    if my_radius > 0: my_start -= math.pi
    my_end = my_start + my_subtended

I have run this on a number of examples and the differences from this code and bulge_to_arc with the correction code above are always less than 1e-16

mozman commented 1 month ago

Please provide a simple DXF files that is rendered incorrectly by the drawing add-on. I need a simple visual example to understand this issue. This code is a long time in the repository and behaves as expected for most users (except for two).

mozman commented 1 month ago
  1. The bulge_to_arc() function returns values to create ARC entities, which can only represent counter-clockwise arcs, therefore the start- and end angles are reversed for negative bulge values.

  2. There is no need to rewrite a function that works and is easier to understand.

TinyTrouble commented 1 month ago

The problem here is that the function is equally required for processing polylines where arcs are drawn both clockwise and counter clockwise. Perhaps a little note in the docs to say that the routine is not suitable for bulge elements in a LWPolyline. Alternatively we need a separate LWPolyline version - which is not a rewrite, it is a simplification.

BTW I forgot to say how much I appreciate the work that has gone into Ezdxf. When I started to look at dxf files, I was totally lost in the enormous quantity of junk in a 3 vertex drawing. ezdxf effectively filters out the junk. Thank you

mozman commented 1 month ago
  1. I already added this note, see 4d85d30b8774201521e9ac1af8365f2377544990
  2. The function is suitable for processing cw and ccw bulges, the difference is the swapped start- and end angle.