MoveToOrigin macro

Need help, or want to share a macro? Post here!
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
edwilliams16
Veteran
Posts: 3179
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

MoveToOrigin macro

Post by edwilliams16 »

From https://forum.freecadweb.org/viewtopic. ... 30#p510397

On importing stl, step and other files, objects are sometimes inconveniently located far from the origin. This Macro allow you designate a point in the object and change the object's placement so that it is translated to the origin.

Current options, selecting, then running the macro:
One Vertex - moved to origin
A line - mid-point moved to origin
A face - CG moved to origin
A circle or circular arc - center moved to origin
(double clicking) A shape (solid, shell, compound, compsolid) - CG moved to origin

Please test in your workflow and I will attempt to debug if necessary and/or add a desirable feature. In the final version I'll put debug=False

I assume if this works and is found of interest, I should follow instructions in https://wiki.freecadweb.org/Macro_documentation

If anyone knows how to make the final line

Code: Select all

base.move(-shift)
undoable, it would be a good addition.

EDIT. Undo implemented

Code: Select all

__Title__    = "MoveToOrigin"
__Author__   = "edwilliams16"
__Version__  = "00.01"
__Date__     = "2021.6.15"
debug = True
'''Usage:
This macro will adjust the placement of a shape to place a selected feature at the origin.
One vertex:  - to origin
One line segment - midpoint to origin
One circle - center to origin
One arc of circle - center to origin
One face - CG of face to origin
Three vertices - center of circle through vertices to origin
Shape - CG of shape to origin

If the shape is a BaseFeature inside a body, the base feature's placement in the body is adjusted.
'''

def circumcenter(A, B, C):
    '''Return the circumcenter of three 3D vertices'''
    a2 = (B - C).Length**2
    b2 = (C - A).Length**2
    c2 = (A - B).Length**2
    if a2 * b2 * c2 == 0.0:
        print('Three vertices must be distinct')
        return
    alpha = a2 * (b2 + c2 - a2)
    beta = b2 * (c2 + a2 - b2)
    gamma = c2 * (a2 + b2 - c2)
    return (alpha*A + beta * B + gamma * C)/(alpha + beta + gamma)

def centerofmass(subshapes):
    mass =0.0
    moment = App.Vector(0, 0, 0)
    for sh in subshapes:
        mass += sh.Volume
        moment += sh.Volume * sh.CenterOfMass
    return moment/mass    

selt = Gui.Selection.getSelectionEx()
if len(selt) != 1:
    print('Select one vertex, edge or object\nor three vertices for center of circle')
    shift = App.Vector(0, 0, 0)  # bail and do nothing  
else:
    sel = selt[0]
    if sel.HasSubObjects:
        vv = sel.SubObjects
        if len(vv) ==3 and vv[0].ShapeType == 'Vertex' and   vv[1].ShapeType == 'Vertex' and vv[2].ShapeType == 'Vertex':
            shift = circumcenter(vv[0].Point, vv[1].Point, vv[2].Point)
            if debug: print('Three Vertices')
        elif len(vv) == 1: 
            selected = sel.SubObjects[0]
            if selected.ShapeType == 'Vertex':
                shift = selected.Point
                if debug: print('One vertex')
            elif selected.ShapeType == 'Edge':
                if selected.Curve.TypeId == 'Part::GeomCircle':    #circles and arcs
                     shift = selected.Curve.Center
                     if debug: print('One arc')      
                elif selected.Curve.TypeId == 'Part::GeomLine':
                    shift = (selected.valueAt(selected.FirstParameter) + selected.valueAt(selected.LastParameter))/2 # mid-point
                    if debug: print('One line')
                else:
                    print(f'edge is {selected.Curve.TypeId} not handled')
                    shift = App.Vector(0, 0, 0)  # bail and do nothing
            elif selected.ShapeType == 'Face':
                shift = selected.CenterOfMass #center of face
                if debug: print('One face')
            else:
                print(f'ShapeType {selected.ShapeType} not handled')
                shift = App.Vector(0, 0, 0)  # bail and do nothing
        else:
            print('Wrong number of Selections')
            shift = App.Vector(0, 0, 0)  # bail and do nothing
    else:
        if debug: print(f'ObjectName is {sel.ObjectName}')
        #if sel.ObjectName[0:11] == 'BaseFeature':
        if hasattr(sel.Object, 'Shape'):
            if debug: print('One solid')
            shape = sel.Object.Shape
            if shape.ShapeType == 'Solid' or shape.ShapeType == 'Shell':
                shift = shape.CenterOfMass
            elif shape.ShapeType == 'Compound' or shape.ShapeType == 'CompSolid':
                shift = centerofmass(shape.SubShapes)
            #more cases?
            else:
                print(f'Object ShapeType {sel.Object.Shape.ShapeType} not handled')
                shift = App.Vector(0, 0, 0)  # bail and do nothing                
        else:
            print(f'{sel.ObjectName} is not a shape')
            shift = App.Vector(0, 0, 0)  # bail and do nothing
            
print(f'Shift = {shift}')
base = App.ActiveDocument.getObject(sel.ObjectName).Placement
App.ActiveDocument.openTransaction('Undo Move to Origin')
base.move(-shift)
App.ActiveDocument.commitTransaction()
App.ActiveDocument.recompute()
Last edited by edwilliams16 on Wed Jun 16, 2021 10:44 pm, edited 2 times in total.
duckmug
Posts: 126
Joined: Mon Jun 07, 2021 12:26 am

Re: MoveToOrigin macro

Post by duckmug »

Hi, I attempted to test a previous version earlier and it didn't seem to actually move the line, it was rather moving the camera, if that makes sense.

I had selected the line inside sketch edit mode and ran the macro.

Maybe I am doing something wrong?

I've tried now to run your version from above and got this error:

Code: Select all

  File "<input>", line 52
    print(f'Shift = {shift} to Undo')
    ^
SyntaxError: invalid syntax
I use the latest version of Freecad from the official freecad linux repos.
edwilliams16
Veteran
Posts: 3179
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: MoveToOrigin macro

Post by edwilliams16 »

It's not intended to work on sketches either in or out of edit mode. It is intended for 3D objects in 3D view. Are you somehow using an old version of FreeCAD - I can only understand the syntax error if you are using python2 not python3?

What does

Code: Select all

import sys
sys.version
in the Python console report?

BTW, it moves the object, not the camera.
duckmug
Posts: 126
Joined: Mon Jun 07, 2021 12:26 am

Re: MoveToOrigin macro

Post by duckmug »

edwilliams16 wrote: Wed Jun 16, 2021 4:36 am It's not intended to work on sketches either in or out of edit mode. It is intended for 3D objects in 3D view. Are you somehow using an old version of FreeCAD - I can only understand the syntax error if you are using python2 not python3?

What does

Code: Select all

import sys
sys.version
in the Python console report?

BTW, it moves the object, not the camera.

Code: Select all

'3.8.5 (default, May 27 2021, 13:30:53) \n[GCC 9.3.0]'
edwilliams16
Veteran
Posts: 3179
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: MoveToOrigin macro

Post by edwilliams16 »

I suspect you may be pasting into the Python console, not running it as a macro. If so, put a blank line before the complaining print statement. The REPL doesn’t handle continuations the same as in a file.
duckmug
Posts: 126
Joined: Mon Jun 07, 2021 12:26 am

Re: MoveToOrigin macro

Post by duckmug »

Ah, I was doing that yes, never had this issue before, will keep it in mind from now and on.

Really useful by the way, I was doing this before:

Code: Select all

obj = FreeCADGui.Selection.getSelection()[0]
shp = obj.Shape
center = shp.BoundBox.Center

m = FreeCAD.Matrix()
m.move(center * -1)
movedShape = shp.transformGeometry(m)

new_obj = App.ActiveDocument.addObject('Part::Feature', obj.Name)
new_obj.Shape = movedShape
Last edited by duckmug on Wed Jun 16, 2021 5:58 am, edited 1 time in total.
openBrain
Veteran
Posts: 9041
Joined: Fri Nov 09, 2018 5:38 pm
Contact:

Re: MoveToOrigin macro

Post by openBrain »

edwilliams16 wrote: Wed Jun 16, 2021 2:44 am If anyone knows how to make the final line

Code: Select all

base.move(-shift)
undoable, it would be a good addition.

Code: Select all

App.ActiveDocument.openTransaction('DESCRIPTION')
# undoable code
App.ActiveDocument.commitTransaction()
edwilliams16
Veteran
Posts: 3179
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: MoveToOrigin macro

Post by edwilliams16 »

openBrain wrote: Wed Jun 16, 2021 5:51 am App.ActiveDocument.openTransaction('Undo MoveToOrigin')
base.move(-shift)
App.ActiveDocument.commitTransaction()
[/code]
Hard to believe it is so simple! One minor nit. It works fine, but the tree is left with the object with a recompute check mark. It would be tidier to be rid of this, but I have not succeeded.
drmacro
Veteran
Posts: 8979
Joined: Sun Mar 02, 2014 4:35 pm

Re: MoveToOrigin macro

Post by drmacro »

edwilliams16 wrote:
Where are you keeping the latest version?
Star Trek II: The Wrath of Khan: Spock: "...His pattern indicates two-dimensional thinking."
edwilliams16
Veteran
Posts: 3179
Joined: Thu Sep 24, 2020 10:31 pm
Location: Hawaii
Contact:

Re: MoveToOrigin macro

Post by edwilliams16 »

drmacro wrote: Sat Jun 19, 2021 3:17 pm
Where are you keeping the latest version?
Until I get a wiki page written the OP https://forum.freecadweb.org/viewtopic. ... 50#p510458 is the latest.
It's getting untidy because there are still two threads going...
Post Reply