[Jo...] Posted Friday at 04:00 PM Share Posted Friday at 04:00 PM Hi all, I'm having some trouble establishing a reliable and repeatable workflow for our before-and-after scan comparisons in GOM Software 2022. Currently, we compare two independently acquired 3D meshes to generate a color-coded heat map showing surface deviations, typically to evaluate material added or removed. Our current workflow is: Import both meshes (previous and current scan). Convert the previous scan into nominal CAD to serve as the reference. Recalculate our alignment using Local Best Fit. Recalculate the surface comparisons and deviation labels. Export the inspection report. The problem I'm encountering is that when I import the meshes and convert the reference scan to CAD, the converted CAD sometimes appears offset from its original position in space. When Local Best Fit recalculates, it aligns the current scan to this offset reference. As a result, some deviation labels no longer correspond to their intended measurement locations, while others fail to compute entirely. Because each part has its own unique reference scan, maintaining a single fixed CAD model isn't an option. My questions are: Is there a way to preserve the original mesh coordinates when converting an actual mesh to CAD? Can the two meshes be aligned to one another before converting the reference mesh into CAD? Would a reference-stage comparison or another mesh-to-mesh workflow be more suitable for this application? What would be the recommended approach for automating this process so that surface comparisons, deviation labels, and report pages update reliably for each new pair of scans? Ideally, we'd like to establish a project template or automated workflow where we import two meshes, calculate their differences, and generate a report without manually correcting their positions each time. Any guidance specific to GOM Software 2022 would be greatly appreciated. Thank you! Link to comment https://qualityforum.zeiss.com/topic/27730-mesh-to-mesh-report-and-alignment-structure/ Share on other sites More sharing options...
[DW...] Posted 1 hour ago Share Posted 1 hour ago Please sign in to view this username. I am not sure I understand everything correctly. You bring two STL files into a project presumably that has no CAD file, designate one of the mesh as a reference by turning it into the "CAD", and then a localized best fit recalculates (from what?) the other STL file location. What is the initial alignment? When you transform the STL into the "CAD", the alignment coordinates do not change. Please sign in to view this quote. This is going to need more explanation. If you want the parts to align correctly to an actual CAD (normal to the global axes) without having the CAD present in the project file with the surface comparison, here is my suggestion - 1. Create new project. 2. Import actual 3d CAD file (STP etc) into project. 3. Align the CAD file to whatever orientation your surface to surface comparison project needs by using the menu Operations>Alignment>SingleElementTransformation>SetMatrix. 4. Save this as your CAD alignment template. 5. Import your reference STL file. Menu Operations>Alignment>InitialAlignment>Pre-alignment. This snaps your reference STL to the CAD. 6. Import any other STL files you want, and do recalculate the project. All files are now aligned to the CAD and to each other. 7. Select the entire aligned reference STL file. 8. Menu File>Export>Mesh>STL. 9. Select the radio button "Export in multiple files". Under Export stages, select "All stages." Click OK. 10. Your exported files will retain their new aligned coordinates. Now when you import them into your surface to surface comparison project, they are already best fit aligned to each other. You can set the Operations>Alignment>InitialAlignment>DefineOriginalAlignmentAsInitialAlignment. Also for automation, use the Python editor and record whatever sequence you are doing and then tweak it as needed. Once finished, you can just fire the macro and the magic happens. Link to comment https://qualityforum.zeiss.com/topic/27730-mesh-to-mesh-report-and-alignment-structure/#findComment-157404 Share on other sites More sharing options...
[Jo...] Posted 1 hour ago Author Share Posted 1 hour ago Please sign in to view this username. Our workflow has us comparing scans of previous coating, to the current coating and we derive a deviation as our coating thickness. Since my "cad" or reference is the previous scan, I cannot use a general Cad model of the part for alignment and deviation. I take the previous coating scan and turn that into my reference mesh or cad body. First photo is the previous scan and the next is the current scan. I am assuming it an alignment problem on my master scanning program. Both Scans came from the same program, same fixture etc. My frustrations was from when I would convert my reference scan into CAD, it would get offset from my deviation markers. Although now I believe that the alignment or original coordinate system changes. If you wouldn't mind, where could I see examples of those python scripts? Thanks, Link to comment https://qualityforum.zeiss.com/topic/27730-mesh-to-mesh-report-and-alignment-structure/#findComment-157410 Share on other sites More sharing options...
[DW...] Posted 1 hour ago Share Posted 1 hour ago (edited) Please sign in to view this quote. Please sign in to view this username. You can absolutely use a CAD for part alignment (not deviation) if you follow the directions in the previous post. It looks and sounds like you are trying to use the fixture to keep the location the same from part to part, which is not going to work. You need to have a single source of truth for every part location and that would be to have a separate program as mentioned above. When you export the parts after alignment, they stay in that exact alignment. So when you bring the 1st, 50, 1000 parts into your other template, they would already be aligned each other and your flags would always calculate. You can still do your reference STL to CAD like you do now. The difference being you aren't chasing an alignment and hoping the fixture keeps everything in the same spot. From your screenshot, you would use the editor under the "Scripting" menu. I use a different version than you do but the concept is the same. You can hit the record button for a new Python script and then do whatever is normal to your workflow and then end the recording. You will see a bunch of code that was generated for each thing you did. This is basically allowing you to "look under the hood" at the actual language that is doing the things you are doing graphically (this drop down menu, selecting this thing, pushing this button, etc). From there you can tweak the code (use AI to help you understand by copy/pasting the script into an LLM and ask for explanation and commenting). Once your script is functional and polished, you can just go to that script and hit execute and everything happens line by line. Here is a custom script I made for maintaining part traceability when scanning lots of parts. It prompts the user with a couple of questions, and then you click on the part and it separates that part from the big lot, renames it with the sample number, increments by one, and then exports everything at the end (calculated from the prompts). import gom import tkinter as tk from tkinter import simpledialog, messagebox # Constants EXPORT_DIRECTORY = 'PUT YOUR EXPORT DIRECTORY HERE' def create_option_dialog(title, prompt, options): """Display a dialog to select an option using radio buttons.""" root = tk.Tk() root.withdraw() # Hide the root window selected_option = tk.StringVar(value=options[0]) dialog = tk.Toplevel(root) dialog.title(title) tk.Label(dialog, text=prompt).pack(pady=10) for option in options: rb = tk.Radiobutton(dialog, text=option, variable=selected_option, value=option) rb.pack(anchor=tk.W) tk.Button(dialog, text="Confirm", command=dialog.destroy).pack(pady=10) root.wait_window(dialog) # Wait for the dialog to close return selected_option.get() def get_user_input(title, prompt): """Display a dialog to get user input.""" root = tk.Tk() root.withdraw() # Hide the root window user_input = simpledialog.askstring(title=title, prompt=prompt) return user_input def get_validated_int_input(title, prompt): """Get and validate integer input from the user.""" while True: user_input = get_user_input(title, prompt) if user_input is None: return None # User cancelled try: return int(user_input) except ValueError: messagebox.showerror("Invalid Input", "Please enter a valid integer.") def copy_and_edit_part(file_name): """Copy and edit the selected part.""" try: gom.script.cad.copy_selected_points(select_points_in_copy=True) gom.script.sys.edit_properties(data=[gom.app.project.clipboard.actual_elements['Combined_Mesh_copy']], elem_name=file_name) gom.script.selection3d.deselect_all() messagebox.showinfo("Part Number", f"The assigned part number is: {file_name}") # Notify user of the assigned number except Exception as e: print(f"Error processing part {file_name}: {str(e)}") return False return True def main(): """Main function to execute the mesh processing.""" # Hide the root window before showing the message box root = tk.Tk() root.withdraw() # Hide the root window messagebox.showinfo("Patch Selection", "Please select the first patch to begin numbering.") total_parts = get_validated_int_input("How many parts total are in this scan?", "How many parts total are in this scan?") if total_parts is None: print("User cancelled operation.") return total_parts1 = get_validated_int_input("What is the number of the first sample in this scan?", "What is the number of the first sample in this scan:") if total_parts1 is None: print("User cancelled operation.") return total_parts2 = total_parts + total_parts1 # Get STL output unit stl_output = create_option_dialog("STL Output Unit", "Select STL output unit:", ["inch", "mm"]) # Edit properties for parts try: gom.script.sys.edit_properties(data=[gom.app.project.parts['Part 1'].actual], elem_name='Combined_Mesh') gom.script.sys.edit_properties(data=[gom.app.project.parts['Part 1']], elem_name='Part') except Exception as e: print(f"Error editing properties: {str(e)}") return # Processing parts for n in range(total_parts): gom.script.cad.show_element(elements=[gom.app.project.parts['Part'].actual]) user_input1 = total_parts1 + n # Automatically increment user_input1 file_name = str(user_input1) if not copy_and_edit_part(file_name): return # Exporting and processing remaining parts for n in range(total_parts1, total_parts2): try: gom.script.part.create_new_part(name=f'Part {n}') gom.script.part.add_elements_to_part(elements=[gom.app.project.clipboard.actual_elements[str(n)]], import_mode='new_elements', part=gom.app.project.parts[f'Part {n}']) gom.script.sys.export_stl(bgr_coding=False, binary=True, color=False, directory=EXPORT_DIRECTORY, elements=gom.ElementSelection( {'category': ['key', 'elements', 'part', gom.app.project.parts[f'Part {n}'], 'explorer_category', 'actual_part']}), export_in_one_file=False, export_stages_mode='current', length_unit=stl_output, set_stl_color_bit=False) except Exception as e: print(f"Error exporting STL for Part {n}: {str(e)}") return # Deselect all before the final message gom.script.selection3d.deselect_all() # Successful completion message messagebox.showinfo("Success", "All parts have been processed and exported successfully!") print("All processing completed successfully.") # Cleanly exit after the user clicks OK root.quit() # Exit the Tkinter main loop root.destroy() # Destroy the Tkinter root window and clean up sys.exit(0) # Cleanly exit the script with a success status if __name__ == "__main__": main() Edited 59 minutes ago Link to comment https://qualityforum.zeiss.com/topic/27730-mesh-to-mesh-report-and-alignment-structure/#findComment-157414 Share on other sites More sharing options...
Recommended Posts
Please sign in to comment
You will be able to leave a comment after signing in