Normalise u,v of face

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
kianwee
Posts: 10
Joined: Wed May 07, 2014 7:54 am

Normalise u,v of face

Post by kianwee »

Hi all, I have been trying to subdivide an extrusion shown here:
extrude.png
extrude.png (14.11 KiB) Viewed 2093 times
So I try to subdivide it according to the u v parameter of each face and this is what i got:
subdivide_extrude.png
subdivide_extrude.png (14.55 KiB) Viewed 2093 times
What I realise is that the ParameterRange of each face is not normalise or trimmed (I am not sure how to call it in other CAD program I believe you call it normalise uv) to its domain? As a result some of the u, v i specify are actually outside of the face domain. Is there a way to normalise the surface u, v ? Thanks in advance. I have attached my script here too.

Code: Select all

import FreeCAD
from FreeCAD import Base, Part

def make_polygon(point_list):
    #append the first point as last point to close the polygon
    point_list.append(point_list[0])
    polygon = Part.makePolygon(point_list)
    pface = Part.makeFilledFace(polygon.Edges)
    return pface

def extrude(face, vector, height):
    vec_h = Base.Vector(vector)*height
    extrusion = face.extrude(vec_h)
    return extrusion

def divide_face(face, u_div, v_div):
    #returns a series of polygons 
    pt_list = []
    face_list = []
    
    umin, umax, vmin, vmax = face.ParameterRange
    print face.ParameterRange
    u_seg = (umax-umin)/u_div
    v_seg = (vmax-vmin)/v_div
    for ucnt in range(u_div+1):
        for vcnt in range(v_div+1):
            u = umin + (ucnt*u_seg)
            v = vmin + (vcnt*v_seg)
            print u,v
            print face.isPartOfDomain(u,v)
            pt = face.valueAt(u, v)
            pt_list.append(pt)

    for pucnt in range(u_div):
        for pvcnt in range(v_div):
            pcnt = pucnt*(v_div+1) + pvcnt
            pt1 = pt_list[pcnt]
            pt2 = pt_list[pcnt+v_div+1]
            pt3 = pt_list[pcnt+v_div+2]
            pt4 = pt_list[pcnt+1]
            polygon = Part.makePolygon([pt1, pt2, pt3, pt4,pt1])
            pface = Part.makeFilledFace(polygon.Edges)
            face_list.append(pface)
            Part.show(pface)
        
    return face_list
    
#==============================================================================================================
#main script
#==============================================================================================================
points1 = [(0,50,0), (50,0,0), (100,50,0), (50,100,0)]
f1 = make_polygon(points1)
extrusion = extrude(f1, (1,1,1), 100)

e_faces = extrusion.Faces
Part.show(extrusion)
for f in e_faces:
    divide_face(f, 5, 10)
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Normalise u,v of face

Post by ickby »

u v space is by definition a rectangular area. With two numbers only how would you define a more complex area? This is not possible. What you are looking for are the parametric curves which restricts the face on the underlying surface. (The surface is defined over the full UV space). In 3D those restrictions are the edges, and every edge has a pcurve in the faces surface UV space. However, it is currently not possible to extract those 2D pCurves as FreeCAD API does not yet support 2D geometry types.

You could use pythonOCC to extrct and handle the pcurves.
kianwee
Posts: 10
Joined: Wed May 07, 2014 7:54 am

Re: Normalise u,v of face

Post by kianwee »

But I have manage to do it with this example, a loft surface. Freecad automatically normalive the UV of a complex surface. Is it because of the way the surface is defined ?
loft_subdivide.png
loft_subdivide.png (129.52 KiB) Viewed 2056 times
Anyway I did a work around:
subdivide_extrude_workaround.png
subdivide_extrude_workaround.png (20.57 KiB) Viewed 2056 times
for anyone who is interested I paste the code here:

Code: Select all

import math
from FreeCAD import Base, Part

def make_polygon(point_list):
    #append the first point as last point to close the polygon
    point_list.append(point_list[0])
    polygon = Part.makePolygon(point_list)
    pface = Part.makeFilledFace(polygon.Edges)
    return pface

def extrude(face, vector, height):
    vec_h = Base.Vector(vector)*height
    extrusion = face.extrude(vec_h)
    return extrusion

def grid_face(face, udim, vdim):
    #returns a series of polygons 
    pt_list = []
    face_list = []
    domain_list = []
    umin, umax, vmin, vmax = face.ParameterRange
    u_div = int(math.ceil((umax-umin)/udim))
    v_div = int(math.ceil((vmax-vmin)/vdim))
    for ucnt in range(u_div+1):
        for vcnt in range(v_div+1):
            u = umin + (ucnt*udim)
            v = vmin + (vcnt*vdim)
            domain_list.append(face.isPartOfDomain(u,v))
            pt = face.valueAt(u, v)
            pt_list.append(pt)

    for pucnt in range(u_div):
        for pvcnt in range(v_div):
            pcnt = pucnt*(v_div+1) + pvcnt
            pt1 = pt_list[pcnt]
            pt2 = pt_list[pcnt+v_div+1]
            pt3 = pt_list[pcnt+v_div+2]
            pt4 = pt_list[pcnt+1]
            polygon = Part.makePolygon([pt1, pt2, pt3, pt4,pt1])
            pface = Part.makeFilledFace(polygon.Edges)
            face_list.append(pface)
            
    #intersect the grids and the face so that those grids that are not in the face will be erase
    if domain_list.count(False) > 0:
        intersection_list = []
        for f in face_list:
            intersection = f.common(face)
            if intersection.isValid():
                intersection_list.append(intersection)
            Part.show(intersection)
                
    return intersection_list


#==============================================================================================================
#main script
#==============================================================================================================
points1 = [(0,50,0), (50,0,0),(100,50,0),(100,60,0), (75,60,0),(75,75,0),(50,100,0)]
f1 = make_polygon(points1)
extrusion = extrude(f1, (0,1,1), 100)

e_faces = extrusion.Faces
Part.show(extrusion)
for f in e_faces:
    grid_list = grid_face(f, 20, 20)
    for grid in grid_list:
        if grid.Faces:
            gface = grid.Faces[0]
            midpt = gface.CenterOfMass
            normal = gface.normalAt(0.5,0.5)
            pt_circle = Part.makeCircle(0.5, midpt, normal)
            Part.show(pt_circle)
eason
Posts: 120
Joined: Thu Apr 09, 2015 2:40 am
Location: Taiwan

Re: Normalise u,v of face

Post by eason »

interesting...! :mrgreen: :mrgreen:
ss.png
ss.png (13.96 KiB) Viewed 2049 times
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Normalise u,v of face

Post by ickby »

What do you mean exactly with normalize? UV space is always 2D, it is flat. And the example you showed, the loft, seems to have a rectangular projection in a flat surface, hence it is very likely that it used the whole rectangular UV space. This is Why your mothod works there: UV space is Not Trimmed by pcurves.
kianwee
Posts: 10
Joined: Wed May 07, 2014 7:54 am

Re: Normalise u,v of face

Post by kianwee »

Its kind of different, let me paste the code for the loft surface here. I believe i mean something like reparameterise the surface. If you run the code and print the parameterrange of the face, its [0.0,1.0,0.0,1.0]. The domain of the surface is divided locally within the surface and uv is normalise to 0.0,1.0.

Sorry for being unclear about the issue here, its mainly because I dun fully understand it. But thanks anyway.

Code: Select all

import FreeCAD
from FreeCAD import Base, Part, Draft, MakeBottle

def curve(points):
    geomCurve = Part.BezierCurve()
    geomCurve.setPoles(points)
    edge = Part.Edge(geomCurve)
    return(edge)

def create_hoops(centre_edge, num_seg):
    edge_length = centre_edge.Length
    seg = edge_length/num_seg
    pt_list = []
    hoop_list = []
    for cnt in range(num_seg+1):
        up_vec = Base.Vector(0,0,1)
        #get the parameter by using the length
        parameter = centre_edge.getParameterByLength(cnt*seg)
        #get the tangent and multiply by the up vec to obtain the horizontal vec
        tangent = centre_edge.tangentAt(parameter)
        pt = centre_edge.valueAt(parameter)
        #show the points
        #pt_circle = Part.makeCircle(0.5, pt, Base.Vector(0,0,1))
        #Part.show(pt_circle)
        horz_vec = up_vec.cross(tangent)
        #generate random numbers to create different sizes
        curvature1 = (centre_edge.curvatureAt(parameter)+1)*5
        curvature2 = (centre_edge.curvatureAt(parameter)+1)*1.8
        #create the hoops 
        pt1 = pt.add(horz_vec.multiply(curvature2))
        pt2 = pt.add(horz_vec.multiply(-curvature2))
        pt3 = pt.add(Base.Vector(0,0,1).multiply(curvature1))
        hoop_points = [pt1,pt3,pt2]
        hoop = curve(hoop_points)
        hoop_list.append(hoop)
    return hoop_list

def divide_face(face, u_div, v_div):
    #returns a series of polygons 
    pt_list = []
    polygon_list = []
    print face.ParameterRange
    u_seg = 1.0/u_div
    v_seg = 1.0/v_div
    for ucnt in range(u_div+1):
        for vcnt in range(v_div+1):
            pt = face.valueAt(ucnt*u_seg, vcnt*v_seg)
            pt_list.append(pt)

    for pucnt in range(u_div):
        for pvcnt in range(v_div):
            pcnt = pucnt*(v_div+1) + pvcnt
            pt1 = pt_list[pcnt]
            pt2 = pt_list[pcnt+v_div+1]
            pt3 = pt_list[pcnt+v_div+2]
            pt4 = pt_list[pcnt+1]
            polygon = Part.makePolygon([pt1, pt2, pt3, pt4,pt1])
            polygon_list.append(polygon)
            Part.show(polygon)
        
    return polygon_list

def createpipes(polygon):
    verts = polygon.Vertexes
    pt_list = []
    line_list = []
    for v in verts:
        pt = v.Point
        pt_list.append(pt)
    line1 = Part.makeLine(pt_list[0],pt_list[2])
    line2 = Part.makeLine(pt_list[3],pt_list[1])
    line_list.append(line1)
    line_list.append(line2)
    return line_list

def sweep(traj, profile, makeSolid = True, isFrenet = True):
    sweep_obj = Part.Wire(traj).makePipeShell([profile],makeSolid,isFrenet)
    return sweep_obj

#=================================================================================================================
points = [Base.Vector(-20,0,0), Base.Vector(-5,10,0), Base.Vector(0,0,0), Base.Vector(5,-5,0), Base.Vector(20,0,0)]
#create the centre curve
centre_crv = curve(points)

#create the hoops
hoop_list = create_hoops(centre_crv,10)

loft = Part.makeLoft(hoop_list)

face = loft.Faces[0]

polygon_list= divide_face(face,5,20)

pipe_list = []
for polygon in polygon_list:
    pipes = createpipes(polygon)
    pipe_list.extend(pipes)

sweep_list = []
for pipe in pipe_list:
    base = pipe.Vertexes[0].Point
    direction = pipe.Vertexes[1].Point.sub(pipe.Vertexes[0].Point) 
    profile = Part.Wire(Part.makeCircle(0.1, base, direction))
    sweep_obj = sweep(pipe,profile, isFrenet = False)
    Part.show(sweep_obj)

print "done"
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Normalise u,v of face

Post by ickby »

I think you should read up on parametric surfaces and general UV space. Here two images which show the essence quite well. First the general UV space without any trimming:
parametricsurface.gif
parametricsurface.gif (9.27 KiB) Viewed 2013 times
And then a trimmed UV space:
trimedsurface.gif
trimedsurface.gif (16.81 KiB) Viewed 2013 times
kianwee
Posts: 10
Joined: Wed May 07, 2014 7:54 am

Re: Normalise u,v of face

Post by kianwee »

Hi ickby, thanks alot, I will read up on parametric surfaces to have a better idea.
User avatar
saso
Veteran
Posts: 1924
Joined: Fri May 16, 2014 1:14 pm
Contact:

Re: Normalise u,v of face

Post by saso »

is this maybe about "translational surfaces" and "quadrilateral planar faces"?

https://www.youtube.com/watch?v=5Y6Bb_Ps1Uk
Post Reply