Ever wanted to snap to the arrowheads of a Measure Object? Well, now you can using this script I wrote, which creates Null objects as children of a Measure Object and positions them at its arrowheads' tips (that can then be snapped to using Axis Snap).
Use the Script Manager to copy this script in, name it, save it, and perhaps create a toolbar button for it if it's something you will use often. If you come up with reasonable suggestions for enhancement of this script or find any bugs, please feel free to provide the details in a reply to this post and I will consider implementing/fixing them.
Important note: The Measure Object has to be part of the Object Hierarchy and selected. You can add it to the Object Hierarchy by clicking on the Create Object button after creating the measurement points using the Measure & Construction tool. Also, you can run the script multiple times for the same Measure Object, after changing its points coordinates, in order to get new Null object children to be created at the modified point locations (the positions of existing Null children of the Measure Object will not auto-refresh if the Measure Object's points get modified. This allows for the recording of historic positions of the Measure object's arrowhead points by running the script each time a change is made to the Measure Object's measurement arrows):
nulls_on_measure_object_arrowheads.py
import c4d
import c4d.gui
# Functionality Provided:
# Creates nulls at active Measure Object's arrowhead points. Can be used to allow "Axis Snap" at those points.
# The colors of the nulls will correspond with the (current) colors of the arrows, for clarity.
# The script is written in a "professional" manner (i.e., not as the sort of hack you oft see posted) and contains
# proper comments describing what various code does.
# Also, supports proper Undo functionality, like the existing Core C4D tools
# Create a null object at one of the measure object's arrowheads
def create_null_at_measure_point(measure_obj,null_name,null_pos,color):
# Create the null
null_obj=c4d.BaseObject(c4d.Onull)
# Set various attributes of the null
null_obj.SetName(null_name)
null_obj.SetAbsPos(null_pos)
null_obj[c4d.NULLOBJECT_DISPLAY]=c4d.NULLOBJECT_DISPLAY_POINT # Use "locator" null object shape
null_obj[c4d.ID_BASEOBJECT_USECOLOR]=1 # Automatic
null_obj[c4d.ID_BASEOBJECT_COLOR]=color # Get from measure
# Let's add the new null object as the last child of the Measure Object
# Get the last child of the Measure (if any children are present), otherwise will be set to None
last_child_obj_of_measure=measure_obj.GetDownLast()
# Add the null object to the Object Hierarchy as the last child of the Measure Object
# Note: Setting checknames to True will cause C4D to add a .1, .2, etc., suffix if there is a name collision
doc.InsertObject(null_obj,measure_obj,pred=last_child_obj_of_measure,checknames=True)
# Needs to be called after creation (and insertion into the document, thanks to C4D Cafe user
# MighT for pointing out the UNDO step sequencing with regard to document insertion)
doc.AddUndo(c4d.UNDOTYPE_NEW, null_obj)
# Entry point into script
def main():
# Make sure that there is an active object and that it is a Measure Object
if op is not None and op.GetType()==c4d.ID_MEASURE_OBJECT:
point1_pos=op[c4d.MDATA_MEASURE_PNT1_VECTOR] # Unused, for now
# Start Undoable action
doc.StartUndo()
# If point 2 is in "World Mode"
# BTW: World mode is MDATA_MEASURE_PNT_MODE_FREE (who would have thunk it?!)
if op[c4d.MDATA_MEASURE_PNT1_MODE]==c4d.MDATA_MEASURE_PNT_MODE_FREE:
# Create a locator null at its arrowhead's tip
create_null_at_measure_point(
op,
null_name="Second point tip",
null_pos=op[c4d.MDATA_MEASURE_PNT2_VECTOR],
color=op[c4d.MDATA_MEASURE_COLOR1]) # Use color of second point, that's how C4D has them numbered (COLOR1 is for point 2)
# Is a third point present (and in "World Mode?")
if op[c4d.MDATA_MEASURE_3RD_POINT] and op[c4d.MDATA_MEASURE_PNT2_MODE]==c4d.MDATA_MEASURE_PNT_MODE_FREE:
# Throw a locator null on that puppy, too
create_null_at_measure_point(
op,
null_name="Third point tip",
null_pos=op[c4d.MDATA_MEASURE_PNT3_VECTOR],
color=op[c4d.MDATA_MEASURE_COLOR2]) # Use color of third point, yes COLOR2 is the color of the third point
# Done (with proper undo handling)
doc.EndUndo()
# Trigger UI refresh/repaint
c4d.EventAdd()
else:
c4d.gui.MessageDialog('Please make sure that a Measure Object is the current active selection, before running this script.')
# Execute main()
if __name__=='__main__':
main()