Cutting QR Code - Stuck in Floating Point Hell 😩
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report
Hey all,
I’m a long time software engineer and a fairly recent Fusion 360 user (it’s been about 2.5 years). I mostly use Fusion 360 to create various models and designs for the 3D printing company I work for.
We’re trying to automate a number of manual processes with scripts/add-ins. I’ve been tasked with creating an add-in that can stamp any face with a qr code of varying side length. I started by looking at Patrick Rainsberry’s (tapnair) QRCoder git repository and then settled on my own solution.
I decided to create an add-in that allowed a user to select a face, the depth of the QR code (cut depth) and the size, then would stamp the face with a generated qr code by cutting the white pixels out of the face and leaving the black pixels raised.
This was fairly straight forward. I pulled in the qrcode dependency via pip3 install qrcode --target /project/path to the project to get the QRCode object and filled out the command_execute() method in the commandDialog’s entry.py class.
At a high level my logic to stamp the QR Code is as follows:
- Use the qr code side length to calculate start X and Y and the individual pixel size.
- Convert the QRCode to a matrix and loop through the matrix identifying each white pixel.
- When a white pixel is found, calculate the coordinates needed for the 2 points to draw the pixel.
- Draw a pixel with the two points and the addTwoPointRectangle() method.
- After all white pixels have been drawn, loop through the sketch profiles and add them to an object collection.
- Use the object collection to extrude (cut) the white pixels the depth determined by the user.
At first I thought this was a complete failure as this produced a feature that looked nothing like a qr code, but I quickly realized there wasn’t really any reason this should fail. After a couple of hours of debugging I realized the problem was floating point arithmetic. I had entered floating point hell.
I came to this realization when I added a tiny gap between each pixel and the code looked perfect (minus the gaps). See the image below:
I then removed the gap and diagnosed further. I tried filtering out the smaller profiles and rounding certain calculations. It got me closer to a valid qr code but still nothing that would scan or resemble the code with gaps. This approach however, solidified my suspicion that floating point arithmetic was to blame as I had multiple examples where I’d get qr codes with tiny connected regions and/or features of the qr code that were merged into a single region. See the below photo for an example:
Below are the floating point calculations happening when looping through the matrix:
pixel_size = side_length / qr_code_size
start_x = center.x - (side_length / 2) # center is the center point of the selected face
start_y = center.y - (side_length / 2)
# loop through the col and row of the qr code matrix
# if there’s a white pixel calculate two points and add to the sketch
x0 = start_x + col * pixel_size
y0 = start_y + row * pixel_size
x1 = x0 + pixel_size
y1 = y0 + pixel_size
pt1 = adsk.core.Point3D.create(x0, y0)
pt2 = adsk.core.Point3D.create(x1, y1)
sketch.sketchCurves.sketchLines.addTwoPointRectangle(pt1, pt2)
I can’t seem to get the precision/rounding of the floating point numbers just right. I’ve tried rounding, flooring the number and even using Python’s Decimal object. I understand why this is happening (floating point hell, a common problem in computing) but I can’t seem to eliminate the creation of extra sketch profiles created from precision errors. I’m working in millimeters and the side_length and qr_code_size are variable due to user input. Please can someone help me get out of floating point hell!
Thanks