selfscripted face with hole

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
lagunax
Posts: 55
Joined: Wed May 25, 2022 5:12 pm

selfscripted face with hole

Post by lagunax »

hi all. have a script that creates a some face. but need to draw with hole in it.
have array in type of

Code: Select all

points=
[
	[list of Vectors of outer border],
	[list of Vectors of inner hole]
]
macro like

Code: Select all

class holedface:
	def __init__(self, obj,points)
	    obj.Proxy = self
	    ...
        obj.addProperty("App::PropertyVectorList", "PointList", "Additional", "List of points as [array]")
        obj.PointList = points
        obj.setEditorMode("PointList",2)
class ViewProviderControlFace:
    def __init__(self, obj):
	...
    def attach(self, obj):
    	...
    def updateData(self, fp, prop):
        "If a property of the handled feature has changed we have the chance to handle this here"
        # fp is the handled feature, prop is the name of the property that has changed
        #App.Console.PrintMessage("Change property: " + str(prop) + "\n")
        
        if (str(prop) != "NormalDefault"):
            if str(prop) != "Normal":
                rot=fp.Placement.Rotation
                fp.Normal = rot.multVec(fp.NormalDefault)
                '''
                if str(prop) != "NormalStart":
                    plac=fp.Placement.Base
                    fp.NormalStart = fp.NormalStartDefault + plac
                    fp.NormalEnd = fp.NormalEnd + plac
                '''
            
        if prop == "Shape":
            s = fp.getPropertyByName("Shape")
            self.data.point.setNum(len(fp.getPropertyByName("PointList")))
            
            cnt=0
            for i in s.Vertexes:
                self.data.point.set1Value(cnt,i.X,i.Y,i.Z)
                cnt=cnt+1
            
            for numpoint in range(0,len(fp.getPropertyByName("PointList"))-1):
                self.face.coordIndex.set1Value(numpoint,numpoint)
            self.face.coordIndex.set1Value(numpoint+1,0)
            self.face.coordIndex.set1Value(numpoint+2,-1)

so i can draw solid face with list of vectors of outer border. but how can i make hole?
tried make one list with adding additional edges connecting one point on outer border and on point on inner hole. but it is 2 edges with same vertices and finally this case works wrong (some part of face not show).
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: selfscripted face with hole

Post by onekk »

with a proper order of vertexes this coul be achieved with:

Code: Select all

"""Test Code.

file: 20230128-polygon_with_holes.py

This code was written as an sample code
for "FreeCAD Forum"

Author: Carlo Dormeletti
Copyright: 2023
Licence: CC BY-NC-ND 4.0 IT
"""

import FreeCAD
import FreeCADGui
from FreeCAD import Placement, Rotation, Vector
import Part
from math import pi, sin, cos


DOC_NAME = "test_polygon"

if FreeCAD.ActiveDocument is None:
    FreeCAD.newDocument(DOC_NAME)
 
# test if there is an active document with a "proper" name
if FreeCAD.ActiveDocument.Name == DOC_NAME:
    print("DOC_NAME exist")
else:
    print("DOC_NAME is not active")
    # test if there is a document with a "proper" name
    try:
        FreeCAD.getDocument(DOC_NAME)
    except NameError:
        # print(f"No Document: {DOC_NAME}")
        FreeCAD.newDocument(DOC_NAME)
        # print(f"Document Created: {DOC_NAME}")

        
DOC = FreeCAD.getDocument(DOC_NAME)
GUI = FreeCADGui.getDocument(DOC_NAME)
VIEW = GUI.ActiveView

# list of vertexes or even a simple list of "tuples of coordinates"
face_points = [
    (0,0,0),
    (10,0,0),
    (10,10,0),
    (0,10,0),
    (0,0,0)
]

hole1_points = [
    (5,5,0),
    (7,7,0),
    (4,7,0),
    (5,5,0)
] # same as above


wire = Part.makePolygon(face_points)
face = Part.Face(wire)


hole1 = Part.makePolygon(hole1_points)
face1 = Part.Face(hole1)


hole2 = hole1.copy()
hole2.translate(Vector(0,-3,0))
face2 = Part.Face(hole2)

DOC.recompute()

face_wh = face.cut([face1, face2])

solid = face_wh.extrude(Vector(0, 0, 50))

# uncomment these if you want to see individual components
# face_do = Part.show(face, "face")
# hole1_do = Part.show(face1, "face1_hole")
# face_wh_do = Part.show(face_wh, "face_with_holes")

solid_wh_do = Part.show(solid, "solid_with_holes")

DOC.recompute()

VIEW = FreeCAD.Gui.ActiveDocument.ActiveView
VIEW.viewAxometric()
VIEW.setAxisCross(True)
VIEW.fitAll()

for ease I have used only polygons, but you could create various things, the cut will be done.

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/
lagunax
Posts: 55
Joined: Wed May 25, 2022 5:12 pm

Re: selfscripted face with hole

Post by lagunax »

i see this way, but not that i finaly need. i create fully parametrized object where i need to get and understand about structure, but in your case vertex-structure is too hard to understand and to manipulate. as i see now viewer makes some calculations with edges and there vertices, but finaly can't get how it calculates.
for example, i have array of vertices like in next example and it creates strange face. all vertices follows one by another and edges directions everywhere are same (from first vertice to last). in both right coinciding edges face (circled yellow) looks fine, but left one cuts triangle (circled red). and i can't understand how i need to calculate this vertices order to remove unwanted triangle-hole.

Code: Select all

import Part
from FreeCAD import Vector
hole=[
    Vector (-79.973953, 50.321354, 0.0), 
    Vector (-88.933395, 50.321354, 0.0), 
    Vector (-79.973953, 60.71704434135796, 0.0), 
    Vector (-79.973953, 67.600258, 0.0), 
    Vector (-78.26062431059376, 62.70502914086129, 0.0), 
    Vector (-60.988506, 82.745964, 0.0), 
    Vector (27.752516, 82.745964, 0.0), 
    Vector (76.38942000000002, 50.321354, 0.0), 
    Vector (36.28531300000001, 50.32135400000001, 0.0), 
    Vector (9.13436615542237, 50.321354, 0.0), 
    Vector (-22.305705886726102, 50.321354, 0.0), 
    Vector (-34.407871025094536, 50.321354, 0.0), 
    Vector (-50.64248908776637, 50.321354, 0.0), 
    Vector (-37.94997, 24.936300000000003, 0.0), 
    Vector (-34.407871025094536, 50.321354, 0.0), 
    Vector (-22.305705886726102, 50.321354, 0.0), 
    Vector (-14.698114000000004, 33.469097, 0.0), 
    Vector (9.13436615542237, 50.321354, 0.0), 
    Vector (36.28531300000001, 50.32135400000001, 0.0), 
    Vector (36.285313, 12.563754000000003, 0.0), 
    Vector (-79.973953, 12.563754000000003, 0.0), 
    Vector (-79.973953, 50.321354, 0.0), 
    Vector (-73.92634158150027, 50.321354, 0.0), 
    Vector (-65.04158, 24.936300000000003, 0.0), 
    Vector (-60.585687262534236, 50.321354, 0.0), 
    Vector (-73.92634158150027, 50.321354, 0.0)
]
wire = Part.makePolygon(hole)
face = Part.Face(wire)
solid_wh_do = Part.show(face, "solid_with_holes")
when i create face with my code from topic, then all goes revers: yelloows cuts triangles, but red looks fine
Attachments
Screenshot_20230129_191409.png
Screenshot_20230129_191409.png (164.25 KiB) Viewed 857 times
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: selfscripted face with hole

Post by onekk »

No calculations involved, you pass to makepolygon a list of ordered vertexes, I usually use counterclockwise drawing order.

first vertex and last vertex must be same point to close the polygon.

It is simple enough to be straightforward.

To make a cut shapes must intersect as you cut faces then extrude the resulting face.

Nothing exotic.

Used in this plain way there are no problems.

I don't know if you pass random points if the makepolygon code as a way to guess if there are sequences and try to create polygons, grouping some if them. But I usually don't rely too much on shape recognition algorithms.

Maybe:

Code: Select all

help(Part.makePolygon)
could gave some hints.

Regards

Carlo D.
Last edited by onekk on Sun Jan 29, 2023 9:47 pm, edited 1 time in total.
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/
lagunax
Posts: 55
Joined: Wed May 25, 2022 5:12 pm

Re: selfscripted face with hole

Post by lagunax »

added first vector to end of list 'hole' and nothing changes, still hole in red circle :? also extruded solid have holes in this place
and i need face, not shape :roll:
Attachments
Screenshot_20230129_195650.png
Screenshot_20230129_195650.png (176.78 KiB) Viewed 817 times
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: selfscripted face with hole

Post by onekk »

lagunax wrote: Sun Jan 29, 2023 5:01 pm added first vector to end of list 'hole' and nothing changes, still hole in red circle :? also extruded solid have holes in this place
and i need face, not shape :roll:
Post some code to see what you means, code posted is not creating multiple faces as there are only a makePolygon instance.

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/
edwilliams16
Veteran
Posts: 3106
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: selfscripted face with hole

Post by edwilliams16 »

edwilliams16
Veteran
Posts: 3106
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: selfscripted face with hole

Post by edwilliams16 »

@lagunax

Here's the basic idea:

Code: Select all

doc = App.ActiveDocument
shp = doc.getObject("RegularPolygon").Shape
outerwire = Part.Wire(shp.Edges)
shp = doc.getObject("RegularPolygon001").Shape
innerwire = Part.Wire(shp.Edges)
face = Part.Face([outerwire, innerwire], 'Part::FaceMakerCheese')
Part.show(face, "HoledFace")
Screenshot 2023-01-29 at 1.01.15 PM.png
Screenshot 2023-01-29 at 1.01.15 PM.png (10.6 KiB) Viewed 713 times
Screenshot 2023-01-29 at 1.04.48 PM.png
Screenshot 2023-01-29 at 1.04.48 PM.png (24.96 KiB) Viewed 711 times
Attachments
holedface.FCStd
(4.03 KiB) Downloaded 13 times
lagunax
Posts: 55
Joined: Wed May 25, 2022 5:12 pm

Re: selfscripted face with hole

Post by lagunax »

onekk wrote: Sun Jan 29, 2023 9:49 pm
lagunax wrote: Sun Jan 29, 2023 5:01 pm added first vector to end of list 'hole' and nothing changes, still hole in red circle :? also extruded solid have holes in this place
and i need face, not shape :roll:
Post some code to see what you means, code posted is not creating multiple faces as there are only a makePolygon instance.

Regards

Carlo D.
last used this code

Code: Select all

import Part
from FreeCAD import Vector
hole=[
    Vector (-79.973953, 50.321354, 0.0), 
    Vector (-88.933395, 50.321354, 0.0), 
    Vector (-79.973953, 60.71704434135796, 0.0), 
    Vector (-79.973953, 67.600258, 0.0), 
    Vector (-78.26062431059376, 62.70502914086129, 0.0), 
    Vector (-60.988506, 82.745964, 0.0), 
    Vector (27.752516, 82.745964, 0.0), 
    Vector (76.38942000000002, 50.321354, 0.0), 
    Vector (36.28531300000001, 50.32135400000001, 0.0), 
    Vector (9.13436615542237, 50.321354, 0.0), 
    Vector (-22.305705886726102, 50.321354, 0.0), 
    Vector (-34.407871025094536, 50.321354, 0.0), 
    Vector (-50.64248908776637, 50.321354, 0.0), 
    Vector (-37.94997, 24.936300000000003, 0.0), 
    Vector (-34.407871025094536, 50.321354, 0.0), 
    Vector (-22.305705886726102, 50.321354, 0.0), 
    Vector (-14.698114000000004, 33.469097, 0.0), 
    Vector (9.13436615542237, 50.321354, 0.0), 
    Vector (36.28531300000001, 50.32135400000001, 0.0), 
    Vector (36.285313, 12.563754000000003, 0.0), 
    Vector (-79.973953, 12.563754000000003, 0.0), 
    Vector (-79.973953, 50.321354, 0.0), 
    Vector (-73.92634158150027, 50.321354, 0.0), 
    Vector (-65.04158, 24.936300000000003, 0.0), 
    Vector (-60.585687262534236, 50.321354, 0.0), 
    Vector (-73.92634158150027, 50.321354, 0.0),
    Vector (-79.973953, 50.321354, 0.0)
]
wire = Part.makePolygon(hole)
face = Part.Face(wire)
#solid_wh_do = Part.show(face, "solid_with_holes")
solid = face.extrude(Vector(0, 0, 50))
solid_wh_do = Part.show(solid, "solid_with_holes")
User avatar
onekk
Veteran
Posts: 6144
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: selfscripted face with hole

Post by onekk »

Probably it is not clear enough that you have to state what points are the outer wire and what points are holes.

See the code below, with some abstraction to make things more pythonic.

Code: Select all

import Part
from FreeCAD import Vector

hole=[
    Vector (-79.973953, 50.321354, 0.0), 
    Vector (-88.933395, 50.321354, 0.0), 
    Vector (-79.973953, 60.71704434135796, 0.0), 
    Vector (-79.973953, 67.600258, 0.0), 
    Vector (-78.26062431059376, 62.70502914086129, 0.0), 
    Vector (-60.988506, 82.745964, 0.0), 
    Vector (27.752516, 82.745964, 0.0), 
    Vector (76.38942000000002, 50.321354, 0.0), 
    Vector (36.28531300000001, 50.32135400000001, 0.0), 
    Vector (9.13436615542237, 50.321354, 0.0), 
    Vector (-22.305705886726102, 50.321354, 0.0), 
    Vector (-34.407871025094536, 50.321354, 0.0), 
    Vector (-50.64248908776637, 50.321354, 0.0), 
    Vector (-37.94997, 24.936300000000003, 0.0), 
    Vector (-34.407871025094536, 50.321354, 0.0), 
    Vector (-22.305705886726102, 50.321354, 0.0), 
    Vector (-14.698114000000004, 33.469097, 0.0), 
    Vector (9.13436615542237, 50.321354, 0.0), 
    Vector (36.28531300000001, 50.32135400000001, 0.0), 
    Vector (36.285313, 12.563754000000003, 0.0), 
    Vector (-79.973953, 12.563754000000003, 0.0), 
    Vector (-79.973953, 50.321354, 0.0), 
    Vector (-73.92634158150027, 50.321354, 0.0), 
    Vector (-65.04158, 24.936300000000003, 0.0), 
    Vector (-60.585687262534236, 50.321354, 0.0), 
    Vector (-73.92634158150027, 50.321354, 0.0),
    Vector (-79.973953, 50.321354, 0.0)
]

def show_points(list_of_points, solid=False, thick=10):
    for v_idx, v3d in enumerate(list_of_points):
        vtx = Part.Vertex(v3d)
        Part.show(vtx, f'vtx_{v_idx}')

def make_polygon(points):
    wire = Part.makePolygon(hole)
    face = Part.Face(wire)

    if solid is True:
        solid_wh = face.extrude(Vector(0, 0, thick))
        solid_wh_do = Part.show(solid_wh, "solid_with_holes")


show_points(hole)

#outer_points = []
#face =  make_polygon(outer_point)

# for every hole you SHOULD make a polygon
#hole_points = []
#hole1 = make_polygon(hole_points)

# the cut is better to be done on faces and then extrude to a solid, to avoid coplanar issues

#face_with_holes = face.cut([hole1, hole2, ...])
#solid_wh = face_with_holes.extrude(Vector(0, 0, thick)) 

Code: Select all

help(Part.makePolygon)
will return:

Code: Select all

Help on built-in function makePolygon:

makePolygon(...) method of builtins.tuple instance
    makePolygon(pntslist) -- Make a polygon from a list of points
    
    Args:
        pntslist (list(Vector)): list of Vectors representing the 
            points of the polygon.
    
    Returns:
        Wire: Part.Wire object. If the last point in the list is 
            not the same as the first point, the Wire will not be 
            closed and cannot be used to create a face.
As said in preceding posts.


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/
Post Reply