Creating mirror images of parts

This tool creates the effect of mirroring parts about any plane orthogonal to one of the XYZ axes. It also optionally creates a plane at the plane of symmetry using point parts.

Download tool and icon (2013-3-6)

 

There are two intended uses of the tool:

1. Create a ‘display room’ effect where there is a partial reflection of the model, as seen in the image of the Ford Taurus below.

2. For symmetric models where the plane(s) of symmetry are not the X, Y, Z=0 planes.

 

How to use

First select all the parts that you want to create a mirror image for, then run the tool. A screenshot of the options is below.

Direction to reflect in: (+X, +Y, +Z, -X, -Y, -Z)

How to set mirror location: (Extents of selected parts, Extents of entire model, Specify a value)

X, Y, or Z value: (float) Location of the plane of symmetry if ‘Specify a value’ is chosen

Create symmetry plane: Whether to create a plane part at the plane of symmetry.

 

Other notes

The partial reflection effect is created with a partially-transparent plane at the plane of symmetry. The strength of the reflection can be adjusted by changing the opacity of the plane. The plane is 4x larger than the model extents. It can be changed on line 55 of the code.

The tool attempts to group all the newly-created copy parts into a group. In EnSight 9 this can fail and produce an error message if there are different types of parts. The rest of the tool still works in this case.

The tool attempts to account for the current symmetry state of the model. So it will correctly reflect the shuttle model for example. It may not work in all cases however. The tool can be used multiple times to reflect a reflection. In this case you may need to manually edit the symmetry of the parts to get the effect you want.

This tool was not created for a specific customer need and has not been heavily tested.

 

Recipe

Copy selected parts; activate mirror symmetry, original instance off; use frame mode to move the copy parts to the appropriate position; create a plane using point parts at the plane of symmetry (optional)

 

EnSight versions: 9.2, 10.0
OS: Windows, Linux, Mac

3 thoughts on “Creating mirror images of parts

  1. Aric,

    I tested your script on a huge model with grouped parts and it creashed inmediatelly. The script can’t handle groups. Furthermore the script crashes if no part is selected. I think a script should stop correctly instead of a crash in such a case. I prefer some kind of warning here or maybe a cool comment like “I’ll be back” :)

    So here comes a version with some small modifications:

    #ENSIGHT_USER_DEFINED_BEGIN
    #TEXT=Mirror image
    #TOOLTIP=Creates a mirror and reflection effect
    #ICON=mirror_image.png
    #TYPE=TOOL
    #ENSIGHT_USER_DEFINED_END
    #
    # Written by Aric Meyer
    # v0.92 8/19/2011
    # http://pythonexchange.com/2011/08/19/creating-mirror-images-of-parts/
    #
    from cei.qtgenericdlg import *
    #
    def find_parts(prev=None): # copied from skybox.py
    l = ensight.query_parts(parts="all",client=1)
    out = []
    for i in l:
    out.append(i[0])
    if (prev):
    for i in prev:
    try:
    out.remove(i)
    except:
    pass
    return out
    #
    # GETS THE CURRENT SYMMETRY OF THE SELECTED PARTS
    def test_reflection_state():
    # searches all parts for mirror on, if detect it gets and return the directions for that part only
    selected_part_objs = ensight.objs.core.find_objs(ensight.objs.core.PARTS,filter={ensight.objs.enums.SELECTED: True})
    symm_on = False
    for part in selected_part_objs:
    if part.SYMMETRYTYPE == 1:
    if symm_on == False:
    p = part
    symm_on = True
    if symm_on == False:
    return [False,False,False,False,False,False,False]
    else:
    symm = []
    symm.append(p.SYMMETRYMIRRORX)
    symm.append(p.SYMMETRYMIRRORXY)
    symm.append(p.SYMMETRYMIRRORXYZ)
    symm.append(p.SYMMETRYMIRRORXZ)
    symm.append(p.SYMMETRYMIRRORY)
    symm.append(p.SYMMETRYMIRRORYZ)
    symm.append(p.SYMMETRYMIRRORZ)
    return symm
    #
    # CREATE PLANE POINT PART
    def create_plane(axis,plane_loc,mins,maxs):
    difs=[]
    for i in range(3):
    difs.append(maxs[i]-mins[i])
    difs[i]=difs[i]*4
    plane_coords=[]
    X,Y,Z=[],[],[]
    if ('X' in axis) == False:
    X.append(mins[0]-difs[0])
    X.append(maxs[0]+difs[0])
    X.append(maxs[0]+difs[0])
    X.append(mins[0]-difs[0])
    if 'Z' in axis:
    Y.append(mins[1]-difs[1])
    Y.append(mins[1]-difs[1])
    Y.append(maxs[1]+difs[1])
    Y.append(maxs[1]+difs[1])
    for i in range(4):
    Z.append(plane_loc)
    else:
    Z.append(mins[2]-difs[2])
    Z.append(mins[2]-difs[2])
    Z.append(maxs[2]+difs[2])
    Z.append(maxs[2]+difs[2])
    for i in range(4):
    Y.append(plane_loc)
    else:
    Y.append(mins[1]-difs[1])
    Y.append(maxs[1]+difs[1])
    Y.append(maxs[1]+difs[1])
    Y.append(mins[1]-difs[1])
    Z.append(mins[2]-difs[2])
    Z.append(mins[2]-difs[2])
    Z.append(maxs[2]+difs[2])
    Z.append(maxs[2]+difs[2])
    for i in range(4):
    X.append(plane_loc)
    for i in range(4):
    plane_coords.append(X[i])
    plane_coords.append(Y[i])
    plane_coords.append(Z[i])
    #plane_coords=ensight.query(ensight.TOOL_PARAMS, ensight.TOOL_PLANE)[1]
    ensight.pointpart.select_all_points()
    ensight.pointpart.delete_points()
    # six points (two triangles)
    for i in [0,1,2,0,2,3]:
    ensight.pointpart.add_point([plane_coords[i*3],plane_coords[i*3+1],plane_coords[i*3+2]])
    # get the current partlist
    list = find_parts()
    ensight.pointpart.begin()
    ensight.pointpart.end()
    ensight.pointpart.create("")
    # grab the newly created part number
    obj = find_parts(list)
    # Convert points into triangles
    #ensight.part.select_begin(obj)
    ensight.objs.core.selection(ensight.objs.ENS_PART).addchild(obj,replace=1,record=1)
    ensight.part.modify_begin()
    ensight.part.description('mirror')
    ensight.pointpart.elt_defined_by("mesh_points_totris")
    ensight.part.modify_end()
    #
    # get size of selected parts
    #
    def get_min_max():
    selection = ensight.query_parts(client=1)

    if len( selection ) > 0:
    min_list = []
    max_list = []
    for i in range(0,len(selection)):
    part_info = ensight.query_parts(parts=[ selection[i][3] ],client = 1)
    part_name = part_info[0][3]
    if len( part_info[0][6] ) > 1:
    group_list = part_info[0][6]
    p_list = ensight.query_parts(parts=group_list , client=0)
    mins = p_list[0][2]
    maxs = p_list[0][3]
    for j in range(0, len( p_list ) ):
    tmp_min = p_list[j][2]
    tmp_max = p_list[j][3]
    for k in range(0,3):
    if tmp_min[k] < mins[k]: mins[k] = tmp_min[k] if tmp_max[k] > maxs[k]:
    maxs[k] = tmp_max[k]
    else:
    p_list = ensight.query_parts()
    p_list = ensight.query_parts(parts=[part_name] , client=0)
    mins = p_list[0][2]
    maxs = p_list[0][3]
    for j in range(0, len( p_list ) ):
    tmp_min = p_list[j][2]
    tmp_max = p_list[j][3]
    for k in range(0,3):
    if tmp_min[k] < mins[k]: mins[k] = tmp_min[k] if tmp_max[k] > maxs[k]:
    maxs[k] = tmp_max[k]
    min_list.append( mins )
    max_list.append( maxs )
    for i in range(0,len(min_list)):
    for k in range(0,3):
    if min_list[i][k] < mins[k]: mins[k] = min_list[i][k] if max_list[i][k] > maxs[k]:
    maxs[k] = max_list[i][k]
    return mins,maxs
    else:
    items=[]
    items.append(['TEXT',ITEM_TEXT,"Please select a part!",""])
    warning_gui = CeiQtGenericDialog(items,None,"Warning!","Ok","Cancel")
    warning_gui.doit()
    #
    #
    def show_gui():
    items=[]
    items.append(['text_val',ITEM_TEXT,"This function will create a mirror and reflection effect for all selected parts.",""])
    direction_list=['+X','+Y','+Z','-X','-Y','-Z']
    items.append(['direction_val',ITEM_COMBO,"Direction to reflect in","Direction",0,direction_list])
    option_list=['Extents of selected parts','Extents of entire model','Specify a value']
    items.append(['option_val',ITEM_COMBO,"How to set mirror location:","Mirror coordinate",0,option_list])
    items.append(['coord_val',ITEM_FLT,"X, Y, or Z value (only for 'Specify a value'):","Coordinate of mirror",0,-9e99,9e99])
    default_toggle_flag = 1 # toggle is ON if 1, OFF if 0
    items.append(['toggle_val',ITEM_BOOL,"Create symmetry plane (mirror)","Create mirror part",default_toggle_flag])
    items.append(['text_val',ITEM_TEXT,"\nClick OK to Continue, Cancel to Quit",""])
    a = CeiQtGenericDialog(items,None,"Mirror and reflection effect","OK","Cancel")
    ret = a.doit()
    for i in a.getValues():
    if (i=='direction_val'):
    direction = direction_list[a.getValue(i)]
    elif (i=='option_val'):
    option = a.getValue(i)
    elif (i=='coord_val'):
    mirror_location = a.getValue(i)
    elif (i=='toggle_val'):
    mirror_create = a.getValue(i)
    return ret, direction, option, mirror_location, mirror_create
    #
    selection = ensight.query_parts(client=1)
    if len( selection ) > 0:
    ret,reflection_direction,mirror_type,specified_mirror_location,create_mirror = show_gui()
    else:
    items=[]
    items.append(['TEXT',ITEM_TEXT,"Please select a part!",""])
    warning_gui = CeiQtGenericDialog(items,None,"Warning!","Ok","Cancel")
    warning_gui.doit()
    ret = 0
    #
    if ret > 0:
    #
    p_list = ensight.query_parts()
    dimensions = get_min_max()
    mins = dimensions[0]
    maxs = dimensions[1]
    selected_parts = []
    for part in range(len(p_list)):
    selected_parts.append(p_list[part][0])
    symmetry = test_reflection_state() # [] or [x,xy,xyz,xz,y,yz,z], currently only uses x,y,z
    # copy parts to create reflection, reflect the parts and translate them
    list = find_parts()
    ensight.part.copy()
    obj = find_parts(list)
    ensight.part.select_begin(obj)
    ensight.part.modify_begin()
    ensight.part.symmetry_type("mirror")
    if 'X' in reflection_direction:
    ensight.part.symmetry_mirror_x("ON")
    if symmetry[4] == True:
    ensight.part.symmetry_mirror_xy("ON")
    ensight.part.symmetry_mirror_y("OFF")
    if symmetry[6] == True:
    ensight.part.symmetry_mirror_xz("ON")
    ensight.part.symmetry_mirror_z("OFF")
    if '-' in reflection_direction:
    plane_of_reflection = mins[0]
    else:
    plane_of_reflection = maxs[0]
    elif 'Y' in reflection_direction:
    ensight.part.symmetry_mirror_y("ON")
    if symmetry[0] == True:
    ensight.part.symmetry_mirror_xy("ON")
    ensight.part.symmetry_mirror_x("OFF")
    if symmetry[6] == True:
    ensight.part.symmetry_mirror_yz("ON")
    ensight.part.symmetry_mirror_z("OFF")
    if '-' in reflection_direction:
    plane_of_reflection = mins[1]
    else:
    plane_of_reflection = maxs[1]
    elif 'Z' in reflection_direction:
    ensight.part.symmetry_mirror_z("ON")
    if symmetry[0] == True:
    ensight.part.symmetry_mirror_xz("ON")
    ensight.part.symmetry_mirror_x("OFF")
    if symmetry[4] == True:
    ensight.part.symmetry_mirror_yz("ON")
    ensight.part.symmetry_mirror_y("OFF")
    if '-' in reflection_direction:
    plane_of_reflection = mins[2]
    else:
    plane_of_reflection = maxs[2]
    ensight.part.mirror_original("OFF")
    ensight.part.modify_end()
    if mirror_type == 1: # extents of entire model
    ensight.part.select_all()
    full_p_list = ensight.query_parts()
    for i in range(3):
    min_ext = mins
    max_ext = maxs
    for part in range(len(full_p_list)):
    mn = full_p_list[part][2]
    mx = full_p_list[part][3]
    for i in range(3):
    if mn[i] < min_ext[i]: min_ext[i] = mn[i] if mx[i] > max_ext[i]:
    max_ext[i] = mx[i]
    ensight.part.select_begin(obj)
    if 'X' in reflection_direction:
    if '-' in reflection_direction:
    plane_of_reflection = min_ext[0]
    else:
    plane_of_reflection = max_ext[0]
    elif 'Y' in reflection_direction:
    if '-' in reflection_direction:
    plane_of_reflection = min_ext[1]
    else:
    plane_of_reflection = max_ext[1]
    elif 'Z' in reflection_direction:
    if '-' in reflection_direction:
    plane_of_reflection = min_ext[2]
    else:
    plane_of_reflection = max_ext[2]
    if mirror_type == 2: # specify a value
    plane_of_reflection = specified_mirror_location
    # use frame mode to translate the mirror image
    ensight.view_transf.function("local")
    if 'X' in reflection_direction:
    ensight.view_transf.axis("x")
    ensight.view_transf.translate(2*plane_of_reflection,0,0)
    elif 'Y' in reflection_direction:
    ensight.view_transf.axis("y")
    ensight.view_transf.translate(0.000000e+00,2*plane_of_reflection,0)
    elif 'Z' in reflection_direction:
    ensight.view_transf.axis("z")
    ensight.view_transf.translate(0.000000e+00,0.000000e+00,2*plane_of_reflection)
    if len(p_list) > 1:
    ensight.part.group("reflection")
    else:
    ensight.part.description('reflection')
    ensight.part.select_begin(selected_parts)
    # makes the symmetry plane, or mirror
    if create_mirror == True:
    list = find_parts()
    create_plane(reflection_direction,plane_of_reflection,mins,maxs)
    obj = find_parts(list)
    ensight.part.select_begin(obj)
    ensight.part.modify_begin()
    ensight.part.colorby_rgb(1.0,1.0,1.0)
    ensight.part.colorby_palette("none")
    ensight.part.opaqueness(0.5)
    ensight.part.modify_end()
    ensight.part.select_begin(selected_parts)

Leave a Reply