1

I'm attempting to draw the raster representation of spline curves extracted from DXF files. I've extracted the data from the DXF files using the ezdxf library and I'm using the Python Wand library (ImageMagick) to draw the images. Wand has a spline function but what it draws doesn't always match the curves from the DXF files. This is no surprise since the Wand spline function doesn't have inputs for the knots or the degree of the DXF spline curve. The following images show what the DXF shapes look like. The Wand spline function works well with one example but not another.

The first is a spline oval Oval Example.

Oval Example

The second is a spine rectangle Rectangle Example.

Rectangle Example

The data points and knots from the DXF files for these shapes have been extracted and used in the following sample code which creates sample bitmaps. Even though the knots and degree aren't taken into account the oval renders well test_image_oval.bmp.

test_image_oval.bmp

The rectangle is misshaped at all sides and corners test_image_rect.bmp.

test_image_rect.bmp

The control points are plotted in red The knots are included but not used.

from wand.image import Image
from wand.color import Color
from wand.drawing import Drawing

############################################
point_list_oval =   [   (5.0,              1.5,              0),
                        (5.0,              0.6715728753,     0),
                        (3.8807118745,     0.0,              0),
                        (2.5,              0.0,              0),
                        (1.1192881255,     0.0,              0),
                        (0.0,              0.6715728753,     0),
                        (0.0,              1.5,              0),
                        (0.0,              2.3284271247,     0),
                        (1.1192881255,     3.0,              0),
                        (2.5,              3.0,              0),
                        (3.8807118745,     3.0,              0),
                        (5.0,              2.3284271247,     0),
                        (5.0,              1.5,              0)]

knots_oval       = [0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 4.0]

############################################
point_list_rect =   [(3.75, 0.0, 0),
                     (3.75,             0.0,              0),
                     (0.25,             0.0,              0),
                     (0.25,             0.0,              0),
                     (0.1125,           0.0,              0),
                     (0.0,              0.1125,           0),
                     (0.0,              0.25,             0),
                     (0.0,              0.25,             0),
                     (0.0,              5.75,             0),
                     (0.0,              5.75,             0),
                     (0.0,              5.8875,           0),
                     (0.1125,           6.0,              0),
                     (0.25,             6.0,              0),
                     (0.25,             6.0,              0),
                     (3.75,             6.0,              0),
                     (3.75,             6.0,              0),
                     (3.8875,           6.0,              0),
                     (4.0,              5.8875,           0),
                     (4.0,              5.75,             0),
                     (4.0,              5.75,             0),
                     (4.0,              0.25,             0),
                     (4.0,              0.25,             0),
                     (4.0,              0.1125,           0),
                     (3.8875,           0.0,              0),
                     (3.75,             0.0,              0)]

knots_rect =  [0.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 2.0, 2.0, 2.0, 3.0, 3.0, 3.0, 4.0, 4.0, 4.0, 5.0, 5.0, 5.0, 6.0, 6.0, 6.0, 7.0, 7.0, 7.0, 8.0, 8.0, 8.0, 8.0]


############################################
def draw_spline(img_width, img_height, DPI, point_list, filename):
    POINT_SIZE = 1
    STROKE_WIDTH = 0.5

    img = Image(width=img_width, height=img_height, background=Color('white'))

    # Convert the points to a 96dpi image space, remove the z axis
    converstion_list = []
    for point in point_list:
        point = (int(round(point[0] * DPI)), int(round(point[1] * DPI)))
        converstion_list.append(point)
    point_list = converstion_list

    # Draw the control points
    with Drawing() as draw:
        draw.stroke_width = STROKE_WIDTH
        draw.stroke_color = Color('red')
        draw.fill_color = Color('red')

        print '---------------------'
        print 'image points'
        for point in point_list:
            perim = (point[0] + POINT_SIZE, point[1])
            draw.circle(point, perim)
            print point
        draw(img)

    # draw the bezier path
    with Drawing() as draw:
        draw.stroke_width = STROKE_WIDTH
        draw.stroke_color = Color('green')
        draw.fill_color = Color('transparent')

        draw.bezier(point_list)

        draw(img)

    img.save(filename=filename)

############################################
DPI = 96
draw_spline(577,385, DPI, point_list_oval,'test_image_oval.bmp')
draw_spline(577, 700, DPI, point_list_rect, 'test_image_rect.bmp')

Does anyone have insight on how to use the Wand library to generate a spline curve and take into account the knots and degree along with the data points?

I've also tried using the SciPy library spline function (interpolate.splprep) with limited success. That's an alternative possibility for a solution. Following that path would mean using the SciPy library to interpolate a large set of points and the use the polyline function in Wand to approximate the curve. If anyone is interested I could include that sample code as well but I don't want to muddle the thread too much.

Any insights on Spline and Wand would be greatly appreciated.

Thanks .

emcconville
  • 23,800
  • 4
  • 50
  • 66
jemiah
  • 63
  • 8

1 Answers1

2

The key thing to understand is that bezier is a spline, but not all splines are bezier. So for the DXF, just draw in chunks of four-coordinates, and use the last used point as the first in the next iteration.

# draw the bezier path
with Drawing() as draw:
    draw.stroke_width = STROKE_WIDTH
    draw.stroke_color = Color('green')
    draw.fill_color = Color('transparent')
    chunk = []                   # Prototype a temporary list.
    for points in point_list:    # Iterate over all points.
        chunk.append(points)     # Append to temporary list.
        if len(chunk) == 4:      # Ready to draw?
            draw.bezier(chunk)   # Draw spline segment.
            del chunk[0:3]       # Clear first three items, and reuse last point.
    draw(img)

oval rect

emcconville
  • 23,800
  • 4
  • 50
  • 66
  • It works and it works beautifully. I have a long list of other examples to try this with so I'm going try this on all the rest. Thanks! Now I want to try this same technique with the SciPy solution to see if it will allow me to capture all the measurements I need to take boundary checking. Seriously, my current rep score is to low to mark how useful this answer was. I'd give it 100pts if I could. – jemiah Feb 28 '18 at 20:47
  • I've gone and tried this solution on several other DXF files. It's working on all of them beautifully. I'm very curious about why groups of four were needed to make this work. When you have time it would be awesome to know why the splines need to be processed in groups of four. From your statements it seems you know a lot about DXF files and Spline curves. In my research I didn't see any reference to groups of 4. Where did you learn about it? Thanks – jemiah Mar 01 '18 at 18:42