Making an Add-on for Precision Drawing Tools (CAD)

Hello, I have a few ideas for simulating a 2D editor in Blender. This is an example script I put together that will create a new scene called “2D” and set up an A4 sheet and an orthogonal camera to match. Also lock the 3d rotation (pan with shift+MMB). Then toggle between the 3D and the 2D scene every time it’s run… Maybe this method could be used? Just copy it to the script editor and run.

import bpy

def setup_2d_scene():
    # create 2D scene if it doesn't exist
    if bpy.data.scenes.get("2D") is None:
        bpy.data.scenes.new("2D")

    if bpy.data.cameras.get("Camera-2D") is None:
        cam = bpy.data.cameras.new("Camera-2D")
    else:
        cam = bpy.data.cameras.get("Camera-2D")

    if bpy.data.objects.get("Camera-2D") is None:
        cam_ob = bpy.data.objects.new("Camera-2D", cam)
    else:
        cam_ob = bpy.data.objects.get("Camera-2D")

    if cam_ob not in bpy.data.scenes['2D'].collection.objects.values():
        bpy.data.scenes['2D'].collection.objects.link(cam_ob)

    cam_ob.data.type = 'ORTHO'
    cam_ob.data.ortho_scale = 0.297
    cam_ob.location.xyz = (0,0,2)
    cam_ob.rotation_euler = (0,0,0)

    # A4 300dpi
    bpy.data.scenes['2D'].render.resolution_x = 3508
    bpy.data.scenes['2D'].render.resolution_y = 2480
    
    if bpy.data.meshes.get("Sheet") is None:
        sheet = bpy.data.meshes.new("Sheet")
        
        # A4 landscape size
        sX = 0.297
        sY = 0.210
        
        verts = [
            (-sX/2, -sY/2, 0),
            (-sX/2, sY/2, 0),
            (sX/2, sY/2, 0),
            (sX/2, -sY/2, 0)
        ]
        faces = [(0,1,2,3)]
        
        sheet.from_pydata(verts, [], faces)
        sheet.update(calc_edges=True)
    else:
        sheet = bpy.data.meshes.get("Sheet")
    
    if bpy.data.objects.get("Sheet") is None:
        sheet_ob = bpy.data.objects.new("Sheet", sheet)
    else:
        sheet_ob = bpy.data.objects['Sheet']
    
    if sheet_ob not in bpy.data.scenes['2D'].collection.objects.values():
        bpy.data.scenes['2D'].collection.objects.link(sheet_ob)


def toggle_2d():
    if bpy.context.window.scene.name == 'Scene':
        setup_2d_scene()
        
        # switch to 2D scene
        bpy.context.window.scene = bpy.data.scenes['2D']
        
        for area in bpy.context.screen.areas:
            if area.type == 'VIEW_3D':
                area.spaces.active.region_3d.lock_rotation = True
                area.spaces.active.region_3d.view_perspective = 'CAMERA'
    else:
        bpy.context.window.scene = bpy.data.scenes['Scene']
        for area in bpy.context.screen.areas:
            if area.type == 'VIEW_3D':
                area.spaces.active.region_3d.lock_rotation = False
                area.spaces.active.region_3d.view_perspective = 'PERSP'

toggle_2d()
4 Likes

Thank you - we are nearing the end of a major Refactoring exercise just now, but will look at this very shortly. We will want to add options for different drawing sizes up to A0 and Custom size. We will want to use this code, so can we have permission to build it into our next development phase please?

We are anticipating using 3D objects combined with MeasureIt-Arch routines to show dimensions and hidden lines. This work of yours will give us the basis for drawing layouts.

Cheers, Clock. :tumbler_glass:

3 Likes

We have now released v1.2.0 - not much in the way of new functions, but a major internal improvement in terms of code structure. Some obscure and annoying little niggles have been ironed out and now all functions called from buttons display the equivalent Command Line entry in that section of the UI.

We have also completed a major renaming of variables to make the code easier to read, along with much more strict compliance to Pylint & Black formatters. From now on I have promised @ermo that I will check any new code for compliance, readability and structure & maintain good Docstrings… :innocent:

The new version is on our GitHub, but there are still some issues getting to the Blender Servers, fingers crossed the miscreants who launched the DDoS attacks have crawled back into their filth pits.

Cheers, Clock. :cocktail:

1 Like

@ecke101 Just to let you know I threw this together using your script and a bit of PDT:


Full Render from the Camera you setup in your script

Dead simple, but it shows how your script could be used to make a drawing, we will want to add different drawing sizes and orientations (Landscape & Portrait) - it’s a start. I have not added any hidden lines, or dimensions yet. Eventually I will use MeasureIt-Arch to produce a line drawing, but I don’t have time for that just now.

Cheers Clock.

4 Likes

Nice, no problem using my code, I’m just happy if it can be helpful in some way. One suggestion is that you can use a material with emitter fully white (or whatever color you want) on the sheet objects, and also set the world material to black.

1 Like

I am looking at adding a material in the script and adding suitably rotated lamp, for the render above, I used a Sun Strength 2 rotated 40 degrees about Y axis, gives a good uniform lighting and differentiation on the Iso view. We will work on this over the next few weeks and post results here.

Thanks for letting us use the code! Clock. :+1:

My original idea was that some kind of “2d view object” could be placed in the 3d view and then the script would cut, extract edges and flatten them and then place them on the sheet. I have a script that will do the cutting and flattening parts if you are interested to see it. This means that shaded views cannot be placed ofcourse but in general mechanical drawings don’t have shaded views anyway. The advantage is that you could use emitter materials to get perfectly white/black sheets which look more professional. And also maybe in the future save the extracted lines to SVG, DXF or some other format.

1 Like

Certainly would be - does this create entities that render? MeasureIt-Arch creates GL graphics and has a render option that will produce an image to composit with the background. It also lets you create dashed lines and you can set a material that renders faces white the same as the background.

In my early trials, I used a white background, so no “sheet” object as such. I am also looking at grease pencil to do drawing borders - there are lots of ideas just now that need looking at and a roadmap for progress needs to be defined.

Cheers, Clock.

EDIT:

@BrendonMurphy - are you still interested in us taking on maintenance of MeshTools? I think you mentioned this later on last year… If so, can we have a conversation on this, either here, Chat, or PM?

Yes, you’re right, there are many ways to do this… I will see when I get some time to make a runnable version of my script. But no now that you mention it, it doesn’t create renderable objects. I used it to export lines to DXF.

This is probably a daft thing to do, but I had a go at a little tutorial, there is no commentary yet, I know this would help, but any critiques, either constructive, or down right rude and abusive would be gratefully received:

The idea was to show a basic introduction and workflow, nothing too fancy as this is the first one I have actually managed to finish…

Cheers, Clock. :tumbler_glass:

18 Likes

Just to say, I have altered the video a bit, with some notes, etc. Voicing is a non-starter for me because:

  • I keep getting it wrong, even with a script.
  • I sound like a Muppet - not sure which one though…

So if anyone wants to help here?

Cheers, Fozzy Bear. :bear:

3 Likes

Following a feature request by email from my website, I did a little work involving some difficult sums and serious increase in brain temperature, I came up with this:

So, two circles at any location and diameter - produce all six possible tangents from a given location and the inner and outer inter-circle tangents. Looks like we can now think about writing a specification for a sub-set of tangent routines.

I should appreciate some feedback on what people might want in the way of tangent routines to incorporate into the specification.

Cheers, Clock. :tumbler_glass:

EDIT:

The bonus is that I also get the intersect points for both inner and outer tangents.

4 Likes

Is there some easy way to get the precision value (epsilon) for single precision floats in Python, similar to sys.float_info.epsilon is for double precision? I’m currently just using the value from Wikipedia Machine epsilon (with a small safety margin).

OK, some decisions need to be made, bearing in mind that Blender does not store Arcs or Circles - just chains of edges that represent these features. In order to form tangents, one needs to know the following:

  • Centre of Arc/Circle 1
  • Radius of Arc/Circle 1
  • Centre of Arc/Circle 2
  • Radius of Arc/Circle 2

Therefore I need to have these entered and stored in the UI. One option is that I have, on the UI, two Vectors and two Floats and then set the vectors by entering values, by locating the centre of an arc, or by using cursor position, the later two would be done by adding buttons to act on selections. The radii can be set by interrogating the arcs, as we already do, or by entering a figure.

Would this approach be acceptable? Would you like a different approach? Thoughts are most welcome and don’t be shy!

Cheers, Einstein. :older_man: :brain:

EDIT:

All the maths is now sorted to calculate the inner and outer tangents.

Edit again:

Here is some code to get the X locations of the first two outer tangent points:

# Circle r0
print("Circle r0")
# Get X values
top = (r0**2 * (xp-a)) + (r0 * (yp-b) * sqrt((xp-a)**2 + (yp-b)**2 -r0**2))
bot = (xp-a)**2 + (yp-b)**2
xt1 = round((top/bot) + a,5)
print(xt1)

top = (r0**2 * (xp-a)) - (r0 * (yp-b) * sqrt((xp-a)**2 + (yp-b)**2 -r0**2))
bot = (xp-a)**2 + (yp-b)**2
xt2 = round((top/bot) + a,5)
print(xt2)

@ermo is going to go absolutely nuts when he sees my variable names, but I will alter these before I release anything on un-suspecting users. I have to use this format of code repeatedly, with alterations, to get all 8 points for inner and outer tangents…

3 Likes

I don’t think there is a way to get that value from Python. The value you are using is very likely to be fine on every machine that Blender runs on, for the foreseeable future.

4 Likes

So, some progress - this lot now works, Inner & Outer Tangents and Tangents from a Point:

Now we need to think about the workflow and such matters, thoughts please?

Cheers, Clock. :tumbler_glass:

PS. I need to rest for a while - grey matter is overheating. There are no DocStrings yet, or all the stuff that @ermo will insist (rightly so) that I do to the code… :laughing:

PPS. At the moment it gives you Inner and Outer Tangents - all of them and you would delete the ones you don’t want, this is far easier than trying to work out which ones you do want.

6 Likes

One approach could be to treat every contiguous group of selected points either like a circle or an arc, and abstract from them the radius and position (and arc/circle normal?) parameters. Not sure exactly the math to use, and maybe you’ve already done it this way.

The angle between consecutive edges and their lengths could probably give the circle center. Intersecting lines perpendicular to each edge could do it too. Then the radius could be the average distance from the center to the points.

It would definitely be nice to avoid having to manually enter information about the existing circles/arcs. I think this method would make it possible.

4 Likes

That is going to be my next step, I already have all the code I need from the Arc Centre command in PDT Design - just need to call those routines so you can just select three vertices on any arc and it will fill in the centre and radius. After I have a rest!

Thanks for the comment, Clock. :tea:

EDIT:

On the maths front I do the Arc Centre and Radius with Numpy Arrays & Routines…

5 Likes

And rightly so!

One certainly hopes so…

Need I comment?

I have trouble parsing this statement. Did you mean to write front instead of from? :thinking:

1 Like

I now have this working in all views, including obscurely rotated ones as below:

Now serious testing is required before any more commits to GitHub and maybe to keep @ermo happy I will also add some DocStrings. :rofl:

Cheers, Clock. :sweat_smile: :skull_and_crossbones:

PS. The weird shape represents two arcs and is necessary to align the view, as Blender does not seem able to do this from three vertices…

PPS.

Of course I did… but I am getting old you know!

3 Likes