Skip to content

Instantly share code, notes, and snippets.

@adielfernandez
Created April 23, 2026 15:54
Show Gist options
  • Select an option

  • Save adielfernandez/b901d7acc4a4cc748dbdfa55a8c211d6 to your computer and use it in GitHub Desktop.

Select an option

Save adielfernandez/b901d7acc4a4cc748dbdfa55a8c211d6 to your computer and use it in GitHub Desktop.
Utility script for removing duplicate prime pillars from gcode generated by Simplify3D when printing with dual extruders
#!/usr/bin/env python3
"""
Remove Duplicate Prime Pillars from G-Code
This script parses a gcode file and removes duplicate prime pillar
sections within each layer. It keeps the first "; feature prime pillar" per layer
and removes all subsequent duplicates (from the duplicate's marker to the next
"; feature " line).
Requirements:
Python 3.9 or later (uses pathlib.Path.with_stem())
No external dependencies - uses only the standard library
Usage:
python RemoveDuplicatePrimePillars.py <input.gcode> [--output <output.gcode>] [--dry-run]
NOTE: This was designed for S3D-generated gcode and may not work
correctly with other slicers or custom gcode formats.
Always back up your original files before running the script!
"""
import argparse
import re
import sys
from pathlib import Path
def parse_args():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(
description="Remove duplicate prime pillar sections from G-Code files.",
formatter_class=argparse.RawDescriptionHelpFormatter,
epilog="""
Examples:
python RemoveDuplicatePrimePillars.py print.gcode
python RemoveDuplicatePrimePillars.py print.gcode --output print_cleaned.gcode
python RemoveDuplicatePrimePillars.py print.gcode --dry-run
"""
)
parser.add_argument(
"input",
type=str,
help="Input G-Code file path"
)
parser.add_argument(
"--output", "-o",
type=str,
default=None,
help="Output G-Code file path (default: <input>_cleaned.gcode)"
)
parser.add_argument(
"--dry-run", "-n",
action="store_true",
help="Preview changes without modifying any files"
)
return parser.parse_args()
def find_markers(lines):
"""
Find all layer and feature markers in the gcode.
Returns:
layer_lines: list of (line_number, layer_number) tuples
prime_pillar_lines: list of line numbers with "; feature prime pillar"
feature_lines: list of line numbers with any "; feature " marker
"""
layer_pattern = re.compile(r'^; layer (\d+)')
prime_pillar_marker = "; feature prime pillar"
feature_marker = "; feature "
layer_lines = []
prime_pillar_lines = []
feature_lines = []
for i, line in enumerate(lines):
stripped = line.strip()
# Check for layer marker
layer_match = layer_pattern.match(stripped)
if layer_match:
layer_num = int(layer_match.group(1))
layer_lines.append((i, layer_num))
# Check for prime pillar marker
if stripped == prime_pillar_marker:
prime_pillar_lines.append(i)
# Check for any feature marker
if stripped.startswith(feature_marker):
feature_lines.append(i)
return layer_lines, prime_pillar_lines, feature_lines
def find_duplicates(layer_lines, prime_pillar_lines, feature_lines, total_lines):
"""
Find duplicate prime pillar sections within each layer.
Returns:
List of (start_line, end_line, layer_num) tuples for sections to remove.
start_line is inclusive, end_line is exclusive.
"""
duplicates = []
# Add a virtual "end of file" layer boundary
layer_boundaries = [line_num for line_num, _ in layer_lines]
layer_boundaries.append(total_lines)
for i, (layer_start, layer_num) in enumerate(layer_lines):
layer_end = layer_boundaries[i + 1]
# Find all prime pillars within this layer
pillars_in_layer = [
pp for pp in prime_pillar_lines
if layer_start <= pp < layer_end
]
# If more than one, mark duplicates (skip the first one)
if len(pillars_in_layer) > 1:
for dup_line in pillars_in_layer[1:]:
# Find the next feature marker after this duplicate
next_feature = None
for fl in feature_lines:
if fl > dup_line:
next_feature = fl
break
# If no next feature, extend to layer end
if next_feature is None:
next_feature = layer_end
duplicates.append((dup_line, next_feature, layer_num))
return duplicates
def remove_duplicates(lines, duplicates):
"""
Remove duplicate sections from lines.
Returns:
New list of lines with duplicates removed.
"""
# Create a set of line indices to remove
lines_to_remove = set()
for start, end, _ in duplicates:
for i in range(start, end):
lines_to_remove.add(i)
# Build new lines list excluding removed lines
new_lines = [
line for i, line in enumerate(lines)
if i not in lines_to_remove
]
return new_lines
def main():
args = parse_args()
# Validate input file
input_path = Path(args.input)
if not input_path.exists():
print(f"Error: Input file '{args.input}' not found.", file=sys.stderr)
sys.exit(1)
# Determine output path
if args.output:
output_path = Path(args.output)
else:
output_path = input_path.with_stem(input_path.stem + "_cleaned")
# Read input file
print(f"Reading: {input_path}")
with open(input_path, 'r', encoding='utf-8') as f:
lines = f.readlines()
original_line_count = len(lines)
print(f"Original lines: {original_line_count:,}")
# Find markers
layer_lines, prime_pillar_lines, feature_lines = find_markers(lines)
print(f"Layers found: {len(layer_lines)}")
print(f"Prime pillars found: {len(prime_pillar_lines)}")
# Find duplicates
duplicates = find_duplicates(layer_lines, prime_pillar_lines, feature_lines, len(lines))
if not duplicates:
print("\nNo duplicate prime pillars found. File is clean!")
sys.exit(0)
# Report duplicates
print(f"\nDuplicate prime pillars found: {len(duplicates)}")
# Group by layer for reporting
layers_with_dups = {}
for start, end, layer_num in duplicates:
if layer_num not in layers_with_dups:
layers_with_dups[layer_num] = []
layers_with_dups[layer_num].append((start + 1, end - start)) # +1 for 1-indexed line numbers
for layer_num in sorted(layers_with_dups.keys()):
dups = layers_with_dups[layer_num]
print(f" Layer {layer_num}: {len(dups)} duplicate(s)")
for line_num, line_count in dups:
print(f" - Line {line_num:,} ({line_count} lines)")
# Calculate lines to remove
total_lines_to_remove = sum(end - start for start, end, _ in duplicates)
print(f"\nTotal lines to remove: {total_lines_to_remove:,}")
if args.dry_run:
print("\n[DRY RUN] No changes made.")
sys.exit(0)
# Remove duplicates
new_lines = remove_duplicates(lines, duplicates)
new_line_count = len(new_lines)
# Write output file
print(f"\nWriting: {output_path}")
with open(output_path, 'w', encoding='utf-8') as f:
f.writelines(new_lines)
print(f"New line count: {new_line_count:,}")
print(f"Lines removed: {original_line_count - new_line_count:,}")
print("\nDone!")
if __name__ == "__main__":
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment