Convert from global coordinates to attachment offset coordinates

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
Post Reply
JMG
Posts: 287
Joined: Wed Dec 25, 2013 9:32 am
Location: Spain
Contact:

Convert from global coordinates to attachment offset coordinates

Post by JMG »

Hi!
I'm trying to reference a position (xyz in GCS) as an offset for a datum line (attachment offset), I'm sure there should be a way to convert from global coordinates to object mapping coordinates, but can't find it. Maybe could someone provide some info regarding this?

Thanks!
Javier.
FreeCAD scripts, animations, experiments and more: http://linuxforanengineer.blogspot.com.es/
Open source CNC hot wire cutter project (NiCr): https://github.com/JMG1/NiCr
Exploded Assembly Workbench: https://github.com/JMG1/ExplodedAssembly
smktec
Posts: 327
Joined: Thu Mar 05, 2020 5:37 pm

Re: Convert from global coordinates to attachment offset coordinates

Post by smktec »

the following code moves the Datum Line. If the vector is collinear with the Datum line, the length of the line is changed.

Code: Select all

DL.AttachmentOffset.Base.add(FreeCAD.Vector(10,0,0));App.activeDocument().recompute(None,True,True)
Attachments
DL.FCStd
(10.02 KiB) Downloaded 7 times
edwilliams16
Veteran
Posts: 3111
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: Convert from global coordinates to attachment offset coordinates

Post by edwilliams16 »

JMG wrote: Sat Apr 01, 2023 10:58 pm Hi!
I'm trying to reference a position (xyz in GCS) as an offset for a datum line (attachment offset), I'm sure there should be a way to convert from global coordinates to object mapping coordinates, but can't find it. Maybe could someone provide some info regarding this?

Thanks!
Javier.
Here's an example. Cylinder001 is attached to Cube. I want to change its attachment offset so that it coincides with Cylinder

Code: Select all

doc= App.ActiveDocument
cyl = doc.getObject('Cylinder')
cyl001 = doc.getObject('Cylinder001')
gt = cyl.getGlobalPlacement()
gp = cyl001.getGlobalPlacement()
ap = cyl001.AttachmentOffset
apnew = ap * gp.inverse() * gt
cyl001.AttachmentOffset = apnew
doc.recompute()
My blog article describes the math of compounding placements. https://blog.freecad.org/2023/01/16/the ... n-freecad/

I'm assuming you don't use links, where getGlobalPlacement() doesn't work as desired.
Attachments
changeAttachment.FCStd
(5.69 KiB) Downloaded 10 times
JMG
Posts: 287
Joined: Wed Dec 25, 2013 9:32 am
Location: Spain
Contact:

Re: Convert from global coordinates to attachment offset coordinates

Post by JMG »

Thanks for your help! :D

Here you have the macro that required it: it creates approximated sheet metal bends using datum lines and revolutions, works by selecting one side face (one that has two edges as sheet thickness) and then the edge of the direction you want the bend to go.

Code: Select all

import math as mt
def add_sm_bend(angle=90):
    operation = FreeCAD.Gui.Selection.getSelection()[0]
    body = operation.Body
    for i, obj in enumerate( FreeCAD.Gui.Selection.getSelectionEx()[0].SubObjects):
        if obj.ShapeType == "Face":
            face = obj
            face_name = FreeCAD.Gui.Selection.getSelectionEx()[0].SubElementNames[i]    
        if obj.ShapeType == "Edge":
            datum_edge = obj
                 
    # detect sm thickness
    sm_thk = round(min([i.Length for i in face.Edges]),4)
    #sm_v = sm_edge.valueAt(0.0)-sm_edge.valueAt(sm_edge.Length)
    #radius_vector = (sm_v).normalize()
    radius_vector = (datum_edge.valueAt(datum_edge.Length/2)-face.CenterOfMass).normalize()
    rev_offset = radius_vector*sm_thk*1.5
    def find_edge_ID(obj,edge):
        for i, edge in enumerate(operation.Shape.Edges):
            if round((edge.CenterOfMass - datum_edge.CenterOfMass).Length, 6) == 0:
                edge_name = "Edge"+str(i+1)
                return edge_name

    # create datum line
    bend_axis = body.newObject('PartDesign::Line','BendAxis')
    bend_axis.AttachmentSupport = [operation, find_edge_ID(operation,datum_edge)]
    bend_axis.MapMode="TwoPointLine"
    FreeCAD.ActiveDocument.recompute()
    ax_plm = FreeCAD.Placement( (rev_offset + face.CenterOfMass), face.Rotation)
    bend_axis.AttachmentOffset.Base = (bend_axis.getGlobalPlacement().inverse()*ax_plm).Base
    FreeCAD.ActiveDocument.recompute()
    bend_axis.ViewObject.Visibility = False
    # create revolution 
    rev = body.newObject('PartDesign::Revolution',"SMBend")
    rev.Profile = (operation, face_name)
    rev.ReferenceAxis = bend_axis
    rev.Angle = angle
    FreeCAD.ActiveDocument.recompute()
    # check for inverted bend (there should be a better way to get auto-intersection,but..)
    bend_volume = mt.pi*((2*sm_thk)**2-sm_thk**2)*datum_edge.Length*(angle/360)
    new_ok_v = operation.Shape.Volume + bend_volume
    new_v = rev.Shape.Volume
    rev.Reversed = round(new_ok_v,3)> round(new_v,3)
    FreeCAD.ActiveDocument.recompute()

add_sm_bend(60)

FreeCAD scripts, animations, experiments and more: http://linuxforanengineer.blogspot.com.es/
Open source CNC hot wire cutter project (NiCr): https://github.com/JMG1/NiCr
Exploded Assembly Workbench: https://github.com/JMG1/ExplodedAssembly
Post Reply