Saturday, May 2, 2015

How do I mirror an LDD / LDraw file?

THIS ONLY WORKS FOR BASIC BRICKS/PLATES (and some others) on a boring orientation.  I don't try to figure out how to find a left ring for a right wing, etc., so this won't work for all models.

I made part of a Lego model that I wanted to "mirror", just flip about an axis.  It's "just bricks" so I didn't have to worry about wings or funny shapes or anything.  I'm surprised Lego Digital Designer doesn't have this.

Anyway, I figured the easiest way to do this was to export it into an LDraw (ldr) file, then since that's plain text, just flip the - signs on the appropriate coordinates.

Here's the little program I used to do this (C#, Windows).  After compiling, just say something like:

SimpleLcadMirror infile.ldr outfile.ldr y

Hmm, don't know how to "compile" it you say?  On Windows it's reasonably easy.

Open cmd (win+r, type cmd, press enter)
notepad SimpleLcadMirror.cs
Copy the stuff below into that file and save it
Type this into the cmd and press enter:
    %windir%\Microsoft.NET\Framework\v4.0.30319\csc.exe SimpleLcadMirror.cs
It should compile and give you a SimpleLcadMirror.exe

Then 'just' run it from the cmd line:
SimpleLcadMirror.exe yourfile.ldr newfile.ldr x y

// Simple utility to mirror an LCAD file
using System;
using System.IO;

class MirrorLCad
{
    static void Main(string[] args)
    {
        String filenameIn = null;
        String filenameOut = null;
        bool mirrorX = false;
        bool mirrorY = false;
        bool mirrorZ = false;
        bool round = false;

        if (args == null || args.Length < 3)
        {
            return;
        }

        filenameIn = args[0];
        filenameOut = args[1];
        for (int i = 2; i < args.Length; i++)
        {
            if (args[i].Equals("x"))
            {
                mirrorX = true;
            }
            else if (args[i].Equals("y"))
            {
                mirrorY = true;
            }
            else if (args[i].Equals("z"))
            {
                mirrorZ = true;
            }
            else
            {
                PrintUsage();
                return;
            }
        }

        PrintWarning();

        var inFile = new StreamReader(filenameIn);
        var outFile = new StreamWriter(filenameOut);
        String line;
        while ((line = inFile.ReadLine()) != null)
        {
            // Very boring in line detection, only type one, and only if syntax has no strange stuff
            line = line.TrimStart();
            if (line.StartsWith("1 "))
            {
                string[] parts = line.Split(' ');
                // We care about x, y, z, - 2, 3 & 4
                // 1  x y z a b c d e f g h i 
                if (mirrorX) { parts[2] = mirror(parts[2]); }
                if (mirrorY) { parts[3] = mirror(parts[3]); }
                if (mirrorZ) { parts[4] = mirror(parts[4]); }
                foreach (var part in parts)
                {
                    outFile.Write(part);
                    outFile.Write(' ');
                }
                outFile.WriteLine();
            }
            else
            {
                // Don't do anything to strange line
                outFile.WriteLine(line);
            }
        }
        outFile.Close();
    }

    static String mirror(String value)
    {
        Console.Write('.');
        if (value.StartsWith("-"))
        {
            value = value.Substring(1);
        }
        else
        {
            value = '-' + value;
        }
        return value;
    }

    static void PrintUsage()
    {
        Console.WriteLine("Usage:");
        Console.WriteLine("SimpleLcadMirror   [x] [y] [z]");
        Console.WriteLine("y is vertical, z is depth, x is horizontal");
    }

    static void PrintWarning()
    {
        Console.WriteLine();
        Console.WriteLine("ONLY ARRANGES PARTS POSITIONS, doesn't swap parts (eg: left/right wing, etc)");
        Console.WriteLine("Intended for simple brick/plate structures on a simple axis, square to the grid");
    }
}