[Solved] Draft upgrade to wire

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
jfc4120
Posts: 448
Joined: Sat Jul 02, 2022 11:16 pm

[Solved] Draft upgrade to wire

Post by jfc4120 »

Code: Select all

OS: Windows 10 Version 2009
Word size of FreeCAD: 64-bit
Version: 0.20.29177 (Git)
Build type: Release
Branch: releases/FreeCAD-0-20
Hash: 68e337670e227889217652ddac593c93b5e8dc94
Python 3.8.10, Qt 5.15.2, Coin 4.0.1, Vtk 8.2.0, OCC 7.6.2
Locale: English/United States (en_US)
Installed mods: 
  * Help 1.0.3
The images will explain. Basically if I select group from utilities menu and select draft upgrade it creates a wire.

But in python, i cannot figure out how to do this, instead it creates a block.

What I am after is wire in python, but also delete all in group, but leave the group there empty for further use.

The code I tried:

Code: Select all

Draft.upgrade(group.Group, delete=True, force=None)
But I do want all lines deleted, but the empty group to remain if possible, thanks.

Edit:

If I just use the block, how do you delete everything in the group?
Attachments
What I first have after running the code
What I first have after running the code
ob1.png (22.14 KiB) Viewed 1048 times
What I am after, but using python
What I am after, but using python
ob2.png (12.88 KiB) Viewed 1048 times
What I get so far in python
What I get so far in python
ob3.png (26.75 KiB) Viewed 1048 times
Last edited by jfc4120 on Wed Sep 21, 2022 10:11 pm, edited 1 time in total.
User avatar
onekk
Veteran
Posts: 6146
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Draft upgrade to wire

Post by onekk »

Hello to create a wire you should simply use.

Code: Select all

wire = Part.wire(<edges list>)
It will return a TopoShape wire but edges must be sorted.


It is not difficult, but it depends on what objects you use.

<edges list> have to be TopoShapes, if they are DocumentObjects you have to use their Shape property.

And you have to delete DocumentObjects by inhand.

Hope it helps.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
jfc4120
Posts: 448
Joined: Sat Jul 02, 2022 11:16 pm

Re: Draft upgrade to wire

Post by jfc4120 »

The trouble I have there is how does such a list look like in:

Code: Select all

wire = Part.wire(<edges list>)
I have no problem figuring the X, Y coordinates.

Can variables be dynamic: Like

Code: Select all

for M in range(1, NTIMES + 1):
    line + M = doc.addObject("Part::Line", "myLine")
 
To get for example Line1, Line2, Line3, etc.

All examples I see you have named lines and you have a set amount. But the oblong is dynamic, I am testing with 12 lines, but it could be any multiple of 4, such as 36. So the short examples don't seem to help.

In the example:

Code: Select all

line = doc.addObject("Part::Line", "myLine")
So second line is line2, okay but if you have to hard code a set number of lines, it cannot work with a dynamic number.

Believe me, before I ask here I google, search forum, etc.
User avatar
onekk
Veteran
Posts: 6146
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Draft upgrade to wire

Post by onekk »

jfc4120 wrote: Tue Sep 20, 2022 5:35 am The trouble I have there is how does such a list look like in:
...

It depends, on what you are trying to achieve, and from what you start from:
  • from existing lines created as DocumentObjects
  • from pure datas, as a list of points that are imported from a file
  • from scratch, you have some data and you have to create a polygon using lines.

As example to make something similar to the third:

Code: Select all

import FreeCAD
from FreeCAD import Vector

import Part


def setview():
    """Rearrange View."""
    FreeCAD.Gui.SendMsgToActiveView("ViewFit")
    FreeCAD.Gui.activeDocument().activeView().viewAxometric()

DOC_NAME = "polygontest"

if FreeCAD.ActiveDocument is not None:
    if FreeCAD.ActiveDocument.Name== DOC_NAME:
        FreeCAD.closeDocument(DOC_NAME)

DOC = FreeCAD.newDocument(DOC_NAME)


pl1 = (
        (0.0, 61.43, 0.0),
        (42.80, 61.40, 0.0),
        (71.25, 41.79, 0.0),
        (75.16, 0.0, 0.0),
        (61.76, 0.0, 0.0),
        (43.88, 41.39, 0.0),
        (-1.307, 48.159, 0.0),
        (0.0, 61.43, 0.0)
          )

polyg1 = Part.makePolygon(pl1)
shape1 = Part.show(polyg1, "polygon1")

setview()
would be the most quick way to create something similar to your image.

You could even do something in the hard way, reusing the code above:

Code: Select all

# polyg1 = Part.makePolygon(pl1)
# shape1 = Part.show(polyg1, "polygon1")

lines = []

for p_idx,pt in enumerate(pl1):
	if p_idx < (len(pl1) - 1):
		line = Part.LineSegment(Vector(*pl1[p_idx]), Vector(*pl1[p_idx +1]))
		# Part.show(line.toShape(), f"line_ {p_idx}")
		lines.append(line.toShape())
	else:
	 	pass
wire = Part.Wire(lines)
Part.show(wire, "wire")

setview()

Hope it helps.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
jfc4120
Posts: 448
Joined: Sat Jul 02, 2022 11:16 pm

Re: Draft upgrade to wire

Post by jfc4120 »

I see no documentation of how to generate a list like:

Code: Select all

pl1 = (
        (0.0, 61.43, 0.0),
        (42.80, 61.40, 0.0),
        (71.25, 41.79, 0.0),
        (75.16, 0.0, 0.0),
        (61.76, 0.0, 0.0),
        (43.88, 41.39, 0.0),
        (-1.307, 48.159, 0.0),
        (0.0, 61.43, 0.0)
          )
I can generate a list like:

Code: Select all

multiplelist [[0.0, 88.89999999999999, 0], [44.44999999999999, 76.9896583964366, 0], [0.0, 88.89999999999999, 0], [-127.0, 88.89999999999999, 0], [44.44999999999999, 76.9896583964366, 0], [76.9896583964366, 44.45000000000001, 0], [76.9896583964366, 44.45000000000001, 0], [88.89999999999999, 5.443555022209985e-15, 0], [88.89999999999999, 5.443555022209985e-15, 0], [76.9896583964366, -44.449999999999974, 0], [76.9896583964366, -44.449999999999974, 0], [44.44999999999999, -76.9896583964366, 0], [44.44999999999999, -76.9896583964366, 0], [1.088711004441997e-14, -88.89999999999999, 0], [1.088711004441997e-14, -88.89999999999999, 0], [-126.99999999999999, -88.89999999999999, 0], [-126.99999999999999, -88.89999999999999, 0], [-171.45000000000002, -76.9896583964366, 0], [-171.45000000000002, -76.9896583964366, 0], [-203.98965839643657, -44.45000000000004, 0], [-203.98965839643657, -44.45000000000004, 0], [-215.89999999999998, -1.6330665066629955e-14, 0], [-215.89999999999998, -1.6330665066629955e-14, 0], [-203.9896583964366, 44.45000000000001, 0], [-203.9896583964366, 44.45000000000001, 0], [-171.45000000000005, 76.98965839643657, 0], [-171.45000000000005, 76.98965839643657, 0], [-127.00000000000003, 88.89999999999999, 0]]
I am in a for loop:

Code: Select all

# top code to get inputs

for M in range(1, NTIMES + 1):
    KOUNT = KOUNT + 1
    DEGREE = DEGREE + PART
    TODEGREE = DEGREE + PART
    C1=R*math.cos(math.radians(DEGREE))
    H1=R*math.sin(math.radians(DEGREE))
    A1=H1/math.cos(math.radians(DEG))
    C11=R*math.cos(math.radians(TODEGREE))
    H11=R*math.sin(math.radians(TODEGREE))
    A11=H11/math.cos(math.radians(DEG))
    if M <= SQSTART:
        #group.addObjects(Draft.make_wire([Vector(A1 * convert, C1 * convert, 0), Vector(A11 * convert, C11 * convert, 0)], closed=False))
        group.addObjects([Draft.makeWire([Vector(A1 * convert, C1 * convert, 0), Vector(A11 * convert, C11 * convert, 0)])])
        multlist.append([A1 * convert, C1 * convert, 0])
        multlist.append([A11 * convert, C11 * convert, 0])
        if M == 1:
            print('coord',A1 * convert, C1 * convert, 0)
            #group.addObjects([Draft.makeWire([Vector(x1, y1, z1), Vector(x2, y2, z2)])])

            #group.addObjects(Draft.make_wire([Vector(A1 * convert, C1 * convert, 0), Vector((A1 * convert) - STRT, C1 * convert, 0)], closed=False))
            group.addObjects([Draft.makeWire([Vector(A1 * convert, C1 * convert, 0), Vector((A1 * convert) - STRT, C1 * convert, 0)])])
            multlist.append([A1 * convert, C1 * convert, 0])
            multlist.append([(A1 * convert) - STRT, C1 * convert, 0])
        if M == HTIME:
            print('coord',A1 * convert, C1 * convert, 0)
            #group.addObjects(Draft.make_wire([Vector(A11 * convert, C11 * convert, 0), Vector((A11 * convert) - STRT, C11 * convert, 0)], closed=False))
            group.addObjects([Draft.makeWire([Vector(A11 * convert, C11 * convert, 0), Vector((A11 * convert) - STRT, C11 * convert, 0)])])
            multlist.append([A11 * convert, C11 * convert, 0])
            multlist.append([(A11 * convert) - STRT, C11 * convert, 0])
 
    if M > SQSTART:
        #group.addObjects(Draft.make_wire([Vector(A1 * convert - STRT, C1 * convert, 0), Vector(A11 * convert - STRT, C11 * convert, 0)], closed=False))
        group.addObjects([Draft.makeWire([Vector(A1 * convert - STRT, C1 * convert, 0), Vector(A11 * convert - STRT, C11 * convert, 0)])])
        multlist.append([A1 * convert - STRT, C1 * convert, 0])
        multlist.append([A11 * convert - STRT, C11 * convert, 0])

print('multiplelist', multlist)
Still, it seems there should be an easy way in python to convert to a wire instead of python making it a block.

I am trying now to figure out how to loop over the multilist to generate a wire. Python doesn't make it easy.

If I go this route, I will delete lines like:

Code: Select all

group.addObjects([Draft.makeWire([Vector(A1 * convert, C1 * convert, 0), Vector(A11 * convert, C11 * convert, 0)])])
And then work with the list. Just seems like a lot of work, when all I want to do is convert to wire and delete existing lines in the group.

Edit:

If I can live with block instead of wire, how do you in python delete the group created? That would help. I can live with just deleting the whole group.
User avatar
onekk
Veteran
Posts: 6146
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Draft upgrade to wire

Post by onekk »

The list in my example is a tuple of tuples, simply are coordinates.

Why? because it is more compact, in term of memory usage, but it is read only, a list of list will work and his not "read only" .

I'm not at computer no, no code help.

Later maybe I will read on a decent screen the post and the code.

Regards

Carlo D.
GitHub page: https://github.com/onekk/freecad-doc.
- In deep articles on FreeCAD.
- Learning how to model with scripting.
- Various other stuffs.

Blog: https://okkmkblog.wordpress.com/
heda
Veteran
Posts: 1348
Joined: Sat Dec 12, 2015 5:49 pm

Re: Draft upgrade to wire

Post by heda »

back to the original question...

at least to me it appears that Draft.upgrade does behave as advertised.
if so, you have simply found a feature, or a bug depending if your glass is half full or half empty.

yepp, fc throws some curved balls from time to time,
it is just to go into the mode of improvise, adapt and overcome...

Code: Select all

doc = App.ActiveDocument
[tempwire], _ = Draft.upgrade(doc.Group.Group)
tmpshp = tempwire.Shape
doc.removeObject(tempwire.Name)
wire = Draft.make_wire([vtx.Point for vtx in tmpshp.OrderedVertexes], closed=True, face=False)
doc.Group.removeObjectsFromDocument()
doc.recompute()
so, if draft.upgrade would have worked as advertised, it would have been 3 lines, now it is 3 extra...

"Can variables be dynamic: Like"

nope, are there any programming language out there allowing for "dynamic variable names"?
anyhow, the question is hypothetical, since there are no issues in storing objects dynamically in for example a list,
if you are hellbent on having names attached to it, use a dict...
list and dicts in py have dynamically allocated lengths, just add/remove as desired

Code: Select all

mylines = [doc.addObject('Part::Line') for i in range(ntimes)]
# for the list and
fmt = 'myline{n+1:03d}'.format
therange = range(1, ntimes+1)
mylines = {fmt(n): doc.addObject('Part::Line', fmt(n)) for n in therange}
# for the dict with some tmp vars to shorten the line that matters

at last,
on the fc coding, it helps if one is clear on what is document objects, shapes, part objs, draft objs etc...
is it not so that what you call a block is in fact a part obj wire? (as in obj.Shape.ShapeType prints 'Wire')
python by itself is a concise language by nature, so if your code is not, there probably is a way to make it concise - you just need to figure out how
same goes for fc, there are plenty of helpers allowing for concise constructs (well, most of the time), one just needs to find them (highest probability of finding them is in the py-console in fc with the inline docstrings).
jfc4120
Posts: 448
Joined: Sat Jul 02, 2022 11:16 pm

Re: Draft upgrade to wire

Post by jfc4120 »

It seems python expects you to know the name of what you want to remove, like:

Code: Select all

FreeCAD.ActiveDocument.removeObject("myObjectName")
But is that not a paradox in that when creating objects, such as lines in code, how in the World can you know them by name if you need to remove them later?

An example, it would be nice if this worked:

Code: Select all

grp = App.ActiveDocument.getObject("Group").OutList
for i in grp:
    FreeCAD.ActiveDocument.removeObject(i)
But of course it doesn't. You have to supply a name in quotes. Do you know of a way to remove all objects from a group without knowing the names?

I have Googled this for over 3 hours, nothing.
heda
Veteran
Posts: 1348
Joined: Sat Dec 12, 2015 5:49 pm

Re: Draft upgrade to wire

Post by heda »

hm, maybe read/absorb the code in the post, it is in there...
jfc4120
Posts: 448
Joined: Sat Jul 02, 2022 11:16 pm

Re: Draft upgrade to wire

Post by jfc4120 »

Yes tried code.

Something strange, if I run this code:

Code: Select all

Draft.upgrade(group.Group, delete=True, force=None)
doc.recompute()
time.sleep(3)
grp = App.ActiveDocument.getObject("Group").OutList
for i in grp:
    #grp.removeObjectsFromDocument()
    FreeCAD.ActiveDocument.removeObject(i.Name)

FreeCAD.ActiveDocument.removeObject("Group")
doc.recompute()
In a separate macro it works, it deletes all lines and the Group and leaves the block.

However the same code in (at bottom) of first macro deletes (removes) everything. Any ideas?

Edit:

Or the code somehow runs before block is created.

Edited:

Adding sleep worked, above code edited.

But still python makes a block whereas gui makes a wire? Still any thoughts?
Post Reply