Rich's Seed Eco-Home Design Software: Difference between revisions

From Open Source Ecology
Jump to navigation Jump to search
m (SUPER ALIGN!)
m (SUPER ALIGN!)
Line 19: Line 19:
'''Macro Code:'''
'''Macro Code:'''
{{#code:python|Your Macro Name.FCMacro}}
{{#code:python|Your Macro Name.FCMacro}}
import FreeCAD as App
<pre>import FreeCAD as App
import FreeCADGui as Gui
import FreeCADGui as Gui
from PySide import QtGui, QtCore
from PySide import QtGui, QtCore
Line 136: Line 136:
dock.show()
dock.show()


print("✅ Super Align REFINED panel ready!")
print("✅ Super Align REFINED panel ready!")</pre>

Revision as of 21:46, 7 January 2026

SUPER ALIGN!

I had AI make for me an alignment tool in FreeCAD 1.0 so that it can align a folder of objects with objects, or other folder of objects, so compound objects don't have to be created. Compound objects prevent the editing of component objects that are baked in. Super Align allows for the alignment of folders without creating these compounds.

Instructions:

Run Macro:

-Click Macro > 📝 Macros...
-Copy and Paste the code below in the macro window
-Highlight all the code
-Click Macro > Execute Macro

A window with a red button that says Align! should appear

-Click on the 3D view tab below to get back to your project.

The Align! window should be there. You can minimize it and dock it to other windows.

-Click a point, edge, or face on your movable object
-On Mac, command Click a point, edge, or face on your fixed object
-Click Align!

Macro Code: {{#code:python|Your Macro Name.FCMacro}}

import FreeCAD as App
import FreeCADGui as Gui
from PySide import QtGui, QtCore

def get_parent_container(obj):
    """Find container (Part/Group) one level up, or return obj itself."""
    for container in App.ActiveDocument.Objects:
        if hasattr(container, 'Group') and obj in container.Group:
            return container
    return obj

def super_align():
    sel_ex = Gui.Selection.getSelectionEx()
    if len(sel_ex) != 2:
        print("❌ Ctrl+click point/edge/face on MOVABLE, then FIXED")
        return
    
    # Store visibility states
    original_vis = {}
    for obj in App.ActiveDocument.Objects:
        if hasattr(obj, 'Visibility'):
            original_vis[obj.Name] = obj.Visibility
    
    # Get parents (container or object itself)
    movable_parent = get_parent_container(sel_ex[0].Object)
    fixed_parent = get_parent_container(sel_ex[1].Object)
    
    print(f"MOVABLE: '{movable_parent.Label}' → FIXED: '{fixed_parent.Label}'")
    
    # Get movable objects (whole container or single)
    if hasattr(movable_parent, 'Group') and movable_parent.Group:
        movable_objects = list(movable_parent.Group)
    else:
        movable_objects = [movable_parent]
    
    # Get subelement positions
    def get_sub_pos(sub_ex):
        sub_obj = sub_ex.SubObjects[0]
        if hasattr(sub_obj, 'Point'):
            return sub_obj.Point
        elif hasattr(sub_obj, 'CenterOfMass'):
            return sub_obj.CenterOfMass
        else:
            # Bounding box center
            bb = sub_obj.BoundBox
            return App.Vector((bb.XMin+bb.XMax)/2, (bb.YMin+bb.YMax)/2, (bb.ZMin+bb.ZMax)/2)
    
    movable_pos = get_sub_pos(sel_ex[0])
    fixed_pos = get_sub_pos(sel_ex[1])
    offset = fixed_pos - movable_pos
    
    print(f"📐 Incremental offset: {offset.x:.1f}, {offset.y:.1f}, {offset.z:.1f}")
    
    # INCREMENTAL ALIGNMENT (preserves relative positions)
    aligned_count = 0
    for obj in movable_objects:
        if hasattr(obj, 'Placement'):
            new_base = obj.Placement.Base + offset
            obj.Placement = App.Placement(new_base, obj.Placement.Rotation)
            aligned_count += 1
    
    # Restore visibility
    for name, vis in original_vis.items():
        obj = App.ActiveDocument.getObject(name)
        if obj and hasattr(obj, 'Visibility'):
            obj.Visibility = vis
    
    Gui.Selection.clearSelection()
    Gui.Selection.addSelection(movable_parent)
    print(f"✅ INCREMENTALLY aligned {aligned_count} objects!")

# CREATE REFINED DOCKED PANEL
mw = Gui.getMainWindow()
dock = QtGui.QDockWidget("Super Align", mw)
dock.setObjectName("SuperAlignDock")
dock.setFeatures(QtGui.QDockWidget.DockWidgetMovable | 
                QtGui.QDockWidget.DockWidgetFloatable | 
                QtGui.QDockWidget.DockWidgetClosable)

widget = QtGui.QWidget()
layout = QtGui.QVBoxLayout(widget)

# BIGGER TITLE
title = QtGui.QLabel("Super Align")
title.setStyleSheet("font-weight: bold; font-size: 20px; color: #2E8B57; padding: 5px;")
layout.addWidget(title)

# INSTRUCTIONS (small text under title)
instructions = QtGui.QLabel("""
• Select point/edge/face on movable object
• Select point/edge/face on fixed object  
• Click Align!
""")
instructions.setStyleSheet("font-size: 10px; color: #666; padding: 2px; margin: 0px;")
instructions.setWordWrap(True)
layout.addWidget(instructions)

# THINNER ALIGN BUTTON
align_btn = QtGui.QPushButton("Align!")
align_btn.setToolTip("Ctrl-click movable point/edge/face → Ctrl-click fixed → Align!")
align_btn.clicked.connect(super_align)
align_btn.setStyleSheet("""
    QPushButton { 
        font-weight: bold; 
        min-height: 25px; 
        max-height: 25px; 
        background-color: #FF6B6B; 
        border-radius: 5px;
    }
""")
layout.addWidget(align_btn)

widget.setLayout(layout)
dock.setWidget(widget)
mw.addDockWidget(QtCore.Qt.RightDockWidgetArea, dock)
dock.show()

print("✅ Super Align REFINED panel ready!")