Scripting example and scripting challenge.

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
User avatar
onekk
Veteran
Posts: 6094
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Scripting example and scripting challenge.

Post by onekk »

Hello, this post is a mix between some thing:
  • A Scritping example, that maybe could became a wiki page.
  • A challenge to produce a complete example with some "real challenging solid"
  • A request for help to other user to see if we could code or model a better solid
Starting from:
wh_691.jpg
wh_691.jpg (33.05 KiB) Viewed 3166 times
FS_691-4.png
FS_691-4.png (469.59 KiB) Viewed 3166 times
FS_691-2.png
FS_691-2.png (672.21 KiB) Viewed 3166 times
Some 2nd and third are courtesy of domad, from https://forum.freecadweb.org/viewtopic. ... 25#p472225 and subsequent posts.

Code: Select all

"""test_file.py

   This code was written as an sample code
   for "FreeCAD Scripting Guide"

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

import math
from math import pi, sin, cos, sqrt

import FreeCAD
from FreeCAD import Placement, Rotation, Vector
import Part
import Draft


DOC_NAME = "engine_wheel"

def activate_doc():
    """activate document"""
    FreeCAD.setActiveDocument(DOC_NAME)
    FreeCAD.ActiveDocument = FreeCAD.getDocument(DOC_NAME)
    FreeCADGui.ActiveDocument = FreeCADGui.getDocument(DOC_NAME)
    print("{0} activated".format(DOC_NAME))


def setview():
    """Rearrange View"""
    DOC.recompute()
    VIEW.viewAxometric()
    VIEW.setAxisCross(True)
    VIEW.fitAll()


def deleteObject(obj):
    if hasattr(obj, "InList") and len(obj.InList) > 0:
        for o in obj.InList:
            deleteObject(o)
            try:
                DOC.removeObject(o.Name)
            except RuntimeError as rte:
                errorMsg = str(rte)
                if errorMsg != "This object is currently not part of a document":
                    FreeCAD.Console.PrintError(errorMsg)
                    return False
    return True


def clear_DOC():
    """
    Clear the active DOCument deleting all the objects
    """
    while DOC.Objects:
        obj = DOC.Objects[0]
        name = obj.Name

        if not hasattr(DOC, name):
            continue

        if not deleteObject(obj):
            FreeCAD.Console.PrintError("Exiting on error")
            os.sys.exit()

        DOC.removeObject(obj.Name)

        DOC.recompute()


if FreeCAD.ActiveDocument is None:
    FreeCAD.newDocument(DOC_NAME)
    print("Document: {0} Created".format(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("No Document: {0}".format(DOC_NAME))
        FreeCAD.newDocument(DOC_NAME)
        print("Document Created".format(DOC_NAME))

DOC = FreeCAD.getDocument(DOC_NAME)
GUI = FreeCADGui.getDocument(DOC_NAME)
VIEW = GUI.ActiveView
#print("DOC : {0} GUI : {1}".format(DOC, GUI))
activate_doc()
#print(FreeCAD.ActiveDocument.Name)
clear_DOC()

EPS = 0.001
EPS_C = EPS * -0.5

VZOR = Vector(0, 0, 0)
ROT0 = Rotation(0, 0, 0)
As usual there are some Services lines to make thing easier when developing (they simply empty the existing model to avoid a bunch of new file creation, when relaunching the script during testing).

tangent2C, dest_pt, a2p, make_dbg_mk have served me well during some years, and are useful when calculating points, some of their result could be achieved in a different way, maybe someone has better code or some hints. (This is one of the challenge part)

Code: Select all

def tangent2C(p1, p2, rad1, rad2):
    """calculate four tangent point to join two circles

        Parameters:
        p1    Vector  Center of circle1
        p2    Vector  Center of circle2
        rad1  float   Radius of circle1
        rad2  float   Radius of circle2

        Return:
        tg1, tg2, tg3, tg4 tangent points.

        Note:
        For make calculation not to raise an error (r0 - r1) must be positive
        if rad1 < rad2  rad1 = r1 and rad2 = r0 (tangent points are inverted)

        But putting cc1 as bigger radius circle (BRC in explication below)
        and cc2 as smaller radius circle (SRC in explication below) will
        not "invert" results, order of drawing is not important.
        With above consideration in mind, think as circles are laying on X axis,
        tg1 = BRC upper tangent points and tg3 = SRC upper tangent point
        while tg2 = BRC bottom tangent point and tg4 = SRC bottom tangent points.

    """

    if rad1 > rad2:
        a = p1.x
        b = p1.y
        c = p2.x
        d = p2.y
        r0 = rad1
        r1 = rad2
        rd = (r0 - r1)
    elif rad1 < rad2:
        a = p2.x
        b = p2.y
        c = p1.x
        d = p1.y
        r0 = rad2
        r1 = rad1
        rd = (r0 - r1)
    else:
        a = p2.x
        b = p2.y
        c = p1.x
        d = p1.y
        r0 = rad2
        r1 = rad1
        rd = 1

    icd = sqrt(pow((c - a), 2) + pow((d - b), 2))

    #print("inter center dist: {}".format(icd))

    if icd < r0:
        raise Exception("Circles are intersecting, no way to calc tangents")

    # point where the tangent meets
    xp = (c * r0 - a * r1) / rd
    yp = (d * r0 - b * r1) / rd

    #xpcn = Part.Vertex(Vector(xp,yp))
    #Part.show(xpcn, "Xcenter")

    # Bigger radius circle tangent points
    xpa = xp - a
    ypb = yp - b
    r02 = pow(r0, 2)
    xyfa = pow(xpa, 2) + pow(ypb, 2)
    xysq = sqrt( xyfa - r02)

    x3 = (r02 * xpa + r0 * ypb * xysq) / xyfa + a
    y3 = (r02 * ypb - r0 * xpa * xysq) / xyfa + b

    x4 = (r02 * xpa - r0 * ypb * xysq) / xyfa + a
    y4 = (r02 * ypb + r0 * xpa * xysq) / xyfa + b

    '''
    xp3 = Part.Vertex(Vector(x3, y3, 0))
    Part.show(xp3, "XP3")
    xp4 = Part.Vertex(Vector(x4, y4, 0))
    Part.show(xp4, "XP4")
    '''
    # Smaller radius circle tangent points
    xpc = xp - c
    ypd = yp - d
    r12 = pow(r1, 2)
    xyfa = pow(xpc, 2) + pow(ypd, 2)
    xysq = sqrt( xyfa - r12)

    x5 = (r12 * xpc + r1 * ypd * xysq) / xyfa + c
    y5 = (r12 * ypd - r1 * xpc * xysq) / xyfa + d

    x6 = (r12 * xpc - r1 * ypd * xysq) / xyfa + c
    y6 = (r12 * ypd + r1 * xpc * xysq) / xyfa + d

    '''
    xp5 = Part.Vertex(Vector(x5, y5, 0))
    Part.show(xp5, "XP5")
    xp6 = Part.Vertex(Vector(x6, y6, 0))
    Part.show(xp6, "XP6")
    '''

    return (Vector(x3, y3, 0), Vector(x4, y4, 0), Vector(x5, y5, 0), Vector(x6, y6, 0))


def dest_pt(pt, angle, length):
    """calculate destination point
        Parameters:
        pt    = starting point
        angle =  rad
        length = units
    """

    dpx = pt.x + math.cos(angle) * length
    dpy = pt.y + math.sin(angle) * length

    return Vector(dpx, dpy, pt.z)


def a2p(a, b):
    """Calculate angle given two point in 2d."""
    delta_y = b.y - a.y
    delta_x = b.x - a.x
    return (math.atan2(delta_y, delta_x))


def make_dbg_mk(tgt_pt, anchor, dist, desc):
    """Make a marker to show point position."""
    l0_pos = dest_pt(tgt_pt, math.radians(anchor), dist)
    o_l = Draft.make_label(
        label_type="Custom",
        target_point=tgt_pt,
        placement=l0_pos,
        custom_text=desc
        )
    o_l.ViewObject.ArrowType = "Arrow"
    o_l.ViewObject.ArrowSize = 1
    # o_l.ViewObject.DisplayMode = u"3D text"
    # o_l.ViewObject.TextSize = '2 mm'
[\code]

For now it will produce the hub and the sprocket of the locomotive wheel.

It aims to be parametric so modifying will produce different type of "sprocketed" wheel (Sorry fo the bad term, but finding technical terms on internet is not so easy).

[code]
rim_nrad = 500
rim_hei = 40
rim_thi = 50

hu_rad = 90
hu_irad = 40

hu_lv_rad = 50
hu_lv_irad = 20
hu_lv_ia = 110

hu_thi = 40  # hub thickness

n_sp = 20
The following part make the hub.

Code: Select all

def mk_hub():
    hu_cen = Vector(0, 0, 0)
    hu_lv_cen = Vector(0, hu_lv_ia * -1, 0)

    p3, p4, p5, p6 = tangent2C(hu_cen, hu_lv_cen, hu_rad, hu_lv_rad)

    cir1 = Part.makeCircle(hu_rad, hu_cen)
    cir2 = Part.makeCircle(hu_lv_rad, hu_lv_cen)
    tg1 = Part.LineSegment(p3, p4).toShape()
    tg2 = Part.LineSegment(p5, p6).toShape()
    rt1 = Part.LineSegment(p3, p5).toShape()
    rt2 = Part.LineSegment(p4, p6).toShape()

    elist = (tg1, tg2, rt1, rt2)
    e1list = Part.sortEdges(elist)

    wire = Part.Wire(e1list[0])

    cf1 = Part.makeFace(cir1, "Part::FaceMakerSimple")
    cf2 = Part.makeFace(cir2, "Part::FaceMakerSimple")
    wf1 = Part.makeFace(wire, "Part::FaceMakerSimple")

    sf1 = cf1.extrude(Vector(0, 0, hu_thi))
    sf2 = cf2.extrude(Vector(0, 0, hu_thi))
    sf3 = wf1.extrude(Vector(0, 0, hu_thi))

    r_hub = sf3.fuse([sf1, sf2]).removeSplitter()

    hol1 = Part.makeCylinder(hu_irad, hu_thi + EPS)
    hol1.Placement = Placement(Vector(hu_cen.x, hu_cen.y, EPS_C), ROT0)

    hol2 = Part.makeCylinder(hu_lv_irad, hu_thi + EPS)
    hol2.Placement = Placement(Vector(hu_lv_cen.x, hu_lv_cen.y, EPS_C), ROT0)

    hub = r_hub.cut((hol1, hol2)).removeSplitter()

    return hub
It uses tangent2C to find tangenf of two circles and the extrude circles and a solid made using tangents lines and two other line that join tangents to make a unique solid for the hub.

Original shape is slightly different, so another challenge is to obtain curved edges for the lines and joint them to the circle, using code only, that calculate points and generate proper lines.

This part of code model the sprockets:

Code: Select all

def mk_sprocket(s_fact):
    spr_len = (rim_nrad - rim_hei) - hu_rad + EPS * 2

    fac = pi * 0.25
    s_len = hu_thi * s_fact
    r_ell = Part.Ellipse(Vector(0, 0, 0), hu_thi * 0.45, hu_thi * 0.25)
    r_arc = Part.ArcOfEllipse(r_ell, pi - fac, pi + fac)

    r_usp = r_arc.StartPoint
    r_up_ep = Vector(r_usp.x + s_len, r_usp.y, r_usp.z)
    up_ln = Part.LineSegment(r_usp, r_up_ep)

    r_lsp = r_arc.EndPoint
    r_lo_ep = Vector(r_lsp.x + s_len, r_lsp.y, r_lsp.z)
    lo_ln = Part.LineSegment(r_lsp, r_lo_ep)

    # Part.show(up_ln.toShape(), "up_ln")
    # Part.show(lo_ln.toShape(), "lo_ln")

    m = FreeCAD.Matrix()
    m.rotateY(math.radians(180))

    prb0 = Part.Parabola()
    prb0.Axis = Vector(0, 0, 1)
    prb0.Focal = 1.5

    # Part.show(prb0.toShape(-5,5), "parab")

    prb0.transform(m)

    edge0 = prb0.toShape(r_lsp.y, r_usp.y)

    c_len = edge0.firstVertex().Point.distanceToPoint(r_lo_ep)
    edge0.translate(Vector(c_len, 0, 0))

    el0 = [r_arc.toShape(), lo_ln.toShape(), up_ln.toShape(), edge0]
    el0s = Part.sortEdges(el0)

    wire0 = Part.Wire(el0s[0])

    return wire0
I have used a portion of ellipse for the rear part, a portion of parabola for the front part and two lines that join the sections, there are some "sharp edges" so another challenge will be to smooth these edges, I have thought to discretize the wire and decimate points, using maybe some check about tangency of adjacent points, but is beyond my mathematical skills.

These part compose the wire on which sections of the sprockets are calculated.

I have cheated a little, as shape resemble the model, but is not the same.

This part is creating the sprocket shape using loft, and cheating a little about the tapering, shape could be tuned modifying side lines length (si_le in the code below).

Code: Select all

spr_len = (rim_nrad - rim_hei) - hu_rad + EPS * 2

spr_red = (0.25, 0.20, 0.18, 0.15, 0.12)

pfls = []

for idx, si_le in enumerate(spr_red):
    incr = spr_len / (len(spr_red) - 1)
    pro1 = mk_sprocket(si_le)
    pro1.translate(Vector(0, 0, idx * incr))
    pfls.append(pro1)

    #Part.show(pro1, "profile{}".format(idx))

# print(dir(wire0.BoundBox))

# print(pfls[0].BoundBox.XMin)

loft = Part.makeLoft(pfls, True, True, False)

sp_BB = pfls[0].BoundBox
x_disp = sp_BB.XMin * -1 + (hu_thi - sp_BB.XLength) * 0.5
Note the way to move the sprocket in place, using some BB lengths to determine how much we will move rear part, as front part is varying as parameter s_fact is modifying side lines length, so x_disp (x displacement) variable is used to properly position the sprocket on the hub.

This part will make the proper sprocket spacing them along the radius.

Code: Select all

for rot_p in range(0, n_sp):
    ang_adv = 360 / n_sp
    sprock = loft.copy()
    m = sprock.Placement.Matrix
    m.move(Vector(x_disp, 0, 0))
    m.rotateZ(math.radians(-90))
    m.rotateX(math.radians(-90))
    m.move(Vector(0, hu_rad, 0))
    m.rotateZ(math.radians(ang_adv * rot_p))
    sprock.Placement.Matrix = m

    Part.show(sprock, "sprocket{}".format(rot_p))


hub = mk_hub()

Part.show(hub, "hub")
Now the most challenging parts will be.
  1. Cut sprockets at an appropriate length, as the hub is not circular.
  2. make proper filllets as in the images above
Rim is in progress, maybe if someone has some profile to reproduce of a real locomotive rim, we could make something that "resemble the original".

for now we are here:
sprocketed_wheel1.png
sprocketed_wheel1.png (17.09 KiB) Viewed 3158 times
Hoping to have raised your attention.

This is the code file:
sprocketed_wheel.py
(9.43 KiB) Downloaded 36 times
Fell free to comment the code, and suggest modifications.

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/
heron
Posts: 307
Joined: Mon Apr 20, 2020 5:32 pm

Re: Scripting example and scripting challenge.

Post by heron »

Hello, first of all, congratulations and thanks for this very illustrative topic.
onekk wrote: Fri Jan 14, 2022 11:48 am tangent2C, dest_pt, a2p, make_dbg_mk have served me well during some years, and are useful when calculating points, some of their result could be achieved in a different way, maybe someone has better code or some hints. (This is one of the challenge part)
I can't understand the advanced mathematical and geometric calculations that are inside the tangen2C function, so I accepted the one challengue and I have made a function with simpler calculations.

Code: Select all

import math
from math import sqrt, pow

doc = App.ActiveDocument
pla = App.Placement
rot = App.Rotation
vec = App.Vector

def findPoint(n, X, Y, R, ang) :
    pt = doc.addObject("Part::Vertex", "Vertex"+str(n))   # Create point and place in the circle center
    pt.X = X
    pt.Y = Y
    pt.Placement = pla(vec(R, 0, 0), rot(vec(0, 0, 1),0))   # move length radius
    pt.Placement = pla(vec(0, 0, 0), rot(vec(0, 0, 1), ang), vec(X, Y, 0)).multiply(pt.Placement)   # Incremental angle rotate
    return pt.Shape.Point

def tangent2C(p1, p2, rad1, rad2):

    """calculate four tangent point to join two circles

        Parameters:
        p1    Vector  Center of circle1
        p2    Vector  Center of circle2
        rad1  float   Radius of circle1
        rad2  float   Radius of circle2

        Return:
        tg1, tg2, tg3, tg4 tangent points.
    """
    if p1.x<=p2.x :
        a = p1.x
        b = p1.y
        c = p2.x
        d = p2.y
        r1 = rad1
        r2 = rad2
    else:
        a = p2.x
        b = p2.y
        c = p1.x
        d = p1.y
        r1 = rad2
        r2 = rad1
   
    icd = sqrt(pow((c - a), 2) + pow((d - b), 2))
    ang_inc = math.degrees(math.asin( (d-b) / icd ))
    ang_tan = math.degrees(math.asin( (r1-r2) / icd ))
    ang_pt1_3 = -90 + ang_tan + ang_inc
    ang_pt2_4 = 90 - ang_tan + ang_inc

    tg1 = findPoint(1, a, b, r1, ang_pt1_3)   # Tangency point 1 (circle1)
    tg2 = findPoint(2, a, b, r1, ang_pt2_4)   # Tangency point 2 (circle1)
    tg3 = findPoint(3, c, d, r2, ang_pt1_3)   # Tangency point 3 (circle2)
    tg4 = findPoint(4, c, d, r2, ang_pt2_4)   # Tangency point 4 (circle2)

    doc.recompute()

    return (tg1, tg2, tg3, tg4)

pto = tangent2C(vec(53, -7, 0), vec(-11, -44, 0), 40, 30)
[print(i) for i in pto]
What do you think?
User avatar
onekk
Veteran
Posts: 6094
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Scripting example and scripting challenge.

Post by onekk »

heron wrote: Sat Jan 15, 2022 11:09 pm Hello, first of all, congratulations and thanks for this very illustrative topic.
I can't understand the advanced mathematical and geometric calculations that are inside the tangen2C function, so I accepted the one challengue and I have made a function with simpler calculations.

What do you think?
The complex mathematics was taken from an internet page. I'm not very skilled so when I need something I make some search.

Many thanks, I'm on Mobile so maybe tonight or tomorrow I will have time do study your codr.

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: 3079
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Scripting example and scripting challenge.

Post by edwilliams16 »

I tried my hand at making a cleaner function:

Code: Select all

from math import sqrt
vec = App.Vector

def tangent2C(p1, p2, rad1, rad2):

    """calculate four tangent point to join two circles

        Parameters:
        p1    Vector  Center of circle1
        p2    Vector  Center of circle2
        rad1  float   Radius of circle1
        rad2  float   Radius of circle2

        Return:
        [tg1, tg2, tg3, tg4] tangent points.
        If one circle strictly encloses the other or are they are concentric, return []
    """
    l= (p1-p2).Length
    if abs(rad1 - rad2) > l or l == 0:
        return []
    else:
        c = (rad1-rad2)/l
        s = sqrt(1- c*c)
        n = (p2-p1)/l #unit vector along line of centers
        m = vec(0,0,1).cross(n) #orthogonal vector
        vp = c*n + s*m  #unit vectors from center to tangent points
        vm = c*n - s*m
        return [c1 + rad1*vp, c1 + rad1*vm, c2 + rad2*vp, c2 + rad2*vm]
    

c1 = vec(53, -7, 0)
c2 = vec(-11, -44, 0)
r1 = 40
r2 = 30
pto = tangent2C(c1,c2 ,r1,r2)
for pt in pto:
    print(pt)
It produces the same results, so it's a matter of taste.
Screen Shot 2022-01-20 at 10.12.35 AM.png
Screen Shot 2022-01-20 at 10.12.35 AM.png (31.05 KiB) Viewed 2916 times
User avatar
onekk
Veteran
Posts: 6094
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Scripting example and scripting challenge.

Post by onekk »

Tanks edwiliamd16 this is elegant.

Sadly this post is not having more followers.

Not a problem if contributors will be effective like you.

More to come.

There are some other challenges in such drawing, that are relatively simple using GUI, more dufficult using script as you will havevto select and modify things based on mutual positions.

Thanks and 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/
User avatar
onekk
Veteran
Posts: 6094
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Scripting example and scripting challenge.

Post by onekk »

Hello, some news:

New version 3 of the drawing:
engine_wheel-v3.py
(10.84 KiB) Downloaded 30 times
  • Integrated "elegant" tangent2c from @edwilliams16, many thanks.
  • Added a rim, with a "decent profile", I have found some dimensions around so I have used these in the parameters. I have found that wheels have a minimal diameter after rectification, so I have used nominal (larger) value for diameter.
  • Used a cut solid to trim sprockets at hub, I've used slightly small diameters to have some join allowance to make a good fusion.
  • Added center reinforcement for main axle.
Some images:
eng_whee_v3_l.png
eng_whee_v3_l.png (48.31 KiB) Viewed 2826 times
eng_whee_v3_2.png
eng_whee_v3_2.png (55.18 KiB) Viewed 2826 times

Now it needs to find a way to make fillets for the junctions between sprockets, hub and rim, and add the "counterweight" (is the term correct?).

As usual if someone has a better way to do things, feel free to post some alternative code.

The intention will be to make a good example about Scritpting a "real thing" and "develop" some good "modelling habits", to show FreeCAD capabilities.

Maybe it an utopic goal, but take it "as is".

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: 3079
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Scripting example and scripting challenge.

Post by edwilliams16 »

Code: Select all

def dest_pt(pt, angle, length):
    """calculate destination point
        Parameters:
        pt    = starting point
        angle =  rad
        length = units
    """

    dpx = pt.x + math.cos(angle) * length
    dpy = pt.y + math.sin(angle) * length

    return Vector(dpx, dpy, pt.z)
    #alternatively
    # return App.Placement(pt, App.Rotation(math.degrees(angle), 0, 0)).multVec(App.Vector(length, 0 ,0))
    # This rotates App.Vector(length, 0 ,0) by angle about the z-axis then translates it by pt
Here's a one line alternative to dest_pt The existing code is easier to understand, but commenting on using the FreeCAD Placement might be educational.
User avatar
onekk
Veteran
Posts: 6094
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Scripting example and scripting challenge.

Post by onekk »

edwilliams16 wrote: Sat Jan 22, 2022 1:52 am Here's a one line alternative to dest_pt The existing code is easier to understand, but commenting on using the FreeCAD Placement might be educational.

Code: Select all

def dest_pt(pt, angle, length):
    """Rrotates App.Vector(length, 0 ,0) by angle about the z-axis then translates it by pt

        Parameters:
        pt    = starting point
        angle =  rad
        length = units
    """
    return App.Placement(pt, App.Rotation(math.degrees(angle), 0, 0)).multVec(App.Vector(length, 0 ,0))

So it will be similar to this?

It was a simple workaround, as my Vector math is not very strong, I know that there will be many elegant solutions to my problems, but haven't found any good text to catch the basis of Vector Math, in a "pratical way", usually I'm lost when explanation say as example, "applying theorem x to ..." etc.

Tanks and 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: 3079
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Scripting example and scripting challenge.

Post by edwilliams16 »

I was thinking

Code: Select all

def dest_pt(pt, angle, length):
    """Rotates App.Vector(length, 0 ,0) by angle about the z-axis then translates it by pt

        Parameters:
        pt    = starting point
        angle =  rad
        length = units
    """
      #return App.Vector(pt.x + math.cos(angle) * length,
      #                          pt.y + math.sin(angle) * length,
      #                          pt.z)
      #or
    return App.Placement(pt, App.Rotation(math.degrees(angle), 0, 0)).multVec(App.Vector(length, 0 ,0))
leaving the original coding to both help understand the intent and show the use of App.Placement
User avatar
onekk
Veteran
Posts: 6094
Joined: Sat Jan 17, 2015 7:48 am
Contact:

Re: Scripting example and scripting challenge.

Post by onekk »

edwilliams16 wrote: Sat Jan 22, 2022 9:00 pm I was thinking
...
leaving the original coding to both help understand the intent and show the use of App.Placement
Yes it is an interesting way to show different things, I will incorporate it in the new version, actually the method is slightly different, as I've created intermediate variables, as Line length is way over 79 characters and my editor complains about it.

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