public static void ReimportModel(Model model, string newReimportPath = null)
        {
            var absoluteFilePath = model.absoluteFilePath;
            var relativeFilePath = model.relativeFilePath;

            // Update the file path
            if (newReimportPath != null)
            {
                absoluteFilePath = newReimportPath;
                relativeFilePath = PathUtils.GetRelativePath(Directory.GetCurrentDirectory(), newReimportPath);
            }

            lxfml = ReadFileLogic(relativeFilePath);
            if (lxfml == null)
            {
                lxfml = ReadFileLogic(absoluteFilePath);
            }
            if (lxfml != null)
            {
                pivot = model.pivot;

                // Store the new reimport path so it can be applied to the model if reimport is successful.
                filePath = newReimportPath;

                importSettings.Clear();

                // Make sure we are compatible with models from before ModelGroupImportSettings by adding default import settings.
                if (model.importSettings.Keys.Count == 0)
                {
                    foreach (var group in lxfml.groups)
                    {
                        importSettings.Add(group.number, new ModelGroupImportSettings());
                    }
                }
                else
                {
                    foreach (var entry in model.importSettings)
                    {
                        importSettings.Add(entry.Key, entry.Value);
                    }
                }

                foreach (var group in lxfml.groups)
                {
                    if (!importSettings.ContainsKey(group.number))
                    {
                        importSettings.Add(group.number, new ModelGroupImportSettings());
                    }
                }

                // Check if groups match up with the file.
                // FIXME Next version could include option to match groups up manually.
                // FIXME Check on group name? We do not have direct access to the groups from the model.
                var groupsMatch = true;
                foreach (var entry in importSettings)
                {
                    if (entry.Key >= lxfml.groups.Length)
                    {
                        Debug.LogWarning("Group " + entry.Key + " does not match up with file.");
                        groupsMatch = false;
                    }
                }

                if (!groupsMatch)
                {
                    EditorUtility.DisplayDialog("Reimport failed", "Model groups do not match up with groups in file. Check log for details", "Ok");
                    return;
                }

                ImportModel.model = model;
                group             = null;

                GetWindow <ImportModel>(true, "LEGO Model Importer");
            }
            else
            {
                ShowReadError();
            }
        }
        /// <summary>
        /// Instantiate all bricks and groups in an LXFML document
        /// </summary>
        /// <param name="lxfml">The LXFML document</param>
        /// <param name="nameOfObject">Path of the LXFML document</param>
        public static GameObject InstantiateModel(LXFMLDoc lxfml, string filePath, Model.Pivot pivot, DictionaryIntToModelGroupImportSettings importSettings)
        {
            //Create "root" LXFML gameobject
            GameObject parent = new GameObject(Path.GetFileNameWithoutExtension(filePath));

            Undo.RegisterCreatedObjectUndo(parent, "Model");
            parent.transform.position = Vector3.zero;

            var model = parent.AddComponent <Model>();

            model.absoluteFilePath = filePath;
            model.relativeFilePath = PathUtils.GetRelativePath(Directory.GetCurrentDirectory(), filePath);
            model.pivot            = pivot;
            model.importSettings   = new DictionaryIntToModelGroupImportSettings(importSettings);

            EditorUtility.DisplayProgressBar("Importing", "Creating bricks.", 0.0f);

            var resultBricks = new Dictionary <int, Brick>(lxfml.bricks.Count);

            InstantiateModelBricks(lxfml, importSettings, ref resultBricks);

            EditorUtility.DisplayProgressBar("Importing", "Creating groups.", 0.8f);

            if (resultBricks.Count > 0)
            {
                var bricksWithConnectivity = new HashSet <Brick>();
                var groups = lxfml.groups;

                for (int i = 0; i < groups.Length; i++)
                {
                    var        number      = groups[i].number;
                    GameObject groupParent = InstantiateModelGroup(groups[i], i, parent, filePath, model.relativeFilePath, ref resultBricks, false, importSettings[number]);
                    if (importSettings[number].connectivity)
                    {
                        bricksWithConnectivity.UnionWith(groupParent.GetComponentsInChildren <Brick>());
                    }
                }

                if (bricksWithConnectivity.Count > 0)
                {
                    var sceneBricks = new HashSet <Brick>(StageUtility.GetCurrentStageHandle().FindComponentsOfType <Brick>());
                    DetectConnectivity(bricksWithConnectivity, sceneBricks);
                }


                if (SceneBrickBuilder.GetAutoUpdateHierarchy())
                {
                    var bricks = new HashSet <Brick>();
                    foreach (var pair in resultBricks)
                    {
                        foreach (var part in pair.Value.parts)
                        {
                            if (part.connectivity)
                            {
                                bricks.Add(pair.Value);
                                break;
                            }
                        }
                    }

                    // On import, the model will be positioned weirdly compared to the rest of the scene, so we just ignore all other bricks
                    ModelGroupUtility.RecomputeHierarchy(bricks, false, ModelGroupUtility.UndoBehavior.withoutUndo);
                }
            }

            // Change the pivot.
            if (pivot != Model.Pivot.Original)
            {
                EditorUtility.DisplayProgressBar("Importing", "Computing bounds.", 0.9f);

                var bounds   = ComputeBounds(parent.transform);
                var newPivot = bounds.center;
                switch (pivot)
                {
                case Model.Pivot.BottomCenter:
                {
                    newPivot += -parent.transform.up * bounds.extents.y;
                    break;
                }
                }

                var difference = parent.transform.position - newPivot;

                foreach (Transform child in parent.transform)
                {
                    child.position -= difference;
                }
                parent.transform.position = newPivot;
            }

            // Add LEGOModelAsset component.
            parent.AddComponent <LEGOModelAsset>();

            EditorUtility.ClearProgressBar();

            return(parent);
        }
        private void OnGUI()
        {
            // Find max label width.
            var maxLabelWidth = 110.0f;

            for (int i = 0; i < lxfml.groups.Length; i++)
            {
                var size = EditorStyles.boldLabel.CalcSize(new GUIContent(lxfml.groups[i].name));
                maxLabelWidth = Mathf.Max(maxLabelWidth, size.x);
            }

            minSize = new Vector2(leftMargin + maxLabelWidth + 360, 226);
            maxSize = new Vector2(leftMargin + maxLabelWidth + 360, 2000);

            scrollPosition = GUILayout.BeginScrollView(scrollPosition, false, false);

            GUI.Box(new Rect(20, 20, 100, 100), logoTexture);

            CreateHeaderUI(new Vector2(leftMargin + maxLabelWidth + 20.0f, 100.0f), "Colliders", "Add colliders to bricks.");
            CreateHeaderUI(new Vector2(leftMargin + maxLabelWidth + 50.0f, 100.0f), "Connectivity", "Add connectivity to bricks. Connectivity requires colliders.");

            CreateHeaderUI(new Vector2(leftMargin + maxLabelWidth + 100.0f, 100.0f), "Static", "Make bricks static.");
            CreateHeaderUI(new Vector2(leftMargin + maxLabelWidth + 130.0f, 100.0f), "Lightmapped", "Add lightmap UVs to bricks. Bricks must be static to be lightmapped.");

            CreateHeaderUI(new Vector2(leftMargin + maxLabelWidth + 180.0f, 100.0f), "Randomize Rotation", "Slightly rotate bricks to improve realism.");
            CreateHeaderUI(new Vector2(leftMargin + maxLabelWidth + 230.0f, 100.0f), "Prefer Legacy", "Prefer legacy geometry over new geometry.");
            CreateHeaderUI(new Vector2(leftMargin + maxLabelWidth + 280.0f, 100.0f), "LOD", "LOD 0 includes chamfered edges.\nLOD 1 does not.\nLOD 2 simplifies knobs.");

            // Reserve the space for the GUILayout scroll view.
            GUILayout.Space(135.0f);
            var nextY = 135.0f;

            var showAllBoolsUI = model == null && group == null && lxfml.groups.Length > 1; // When importing a new model, just check if there is more than one lxfml group.

            showAllBoolsUI |= model != null && importSettings.Count > 1;                    // When reimporting an entire model, check if the existing model has more than one group.
            if (showAllBoolsUI)
            {
                CreateAllBoolsUI(new Vector2(leftMargin + maxLabelWidth + 15.0f, nextY), importSettings, "colliders", "connectivity", null);
                CreateAllBoolsUI(new Vector2(leftMargin + maxLabelWidth + 45.0f, nextY), importSettings, "connectivity", null, "colliders");

                CreateAllBoolsUI(new Vector2(leftMargin + maxLabelWidth + 95.0f, nextY), importSettings, "isStatic", "lightmapped", null);
                CreateAllBoolsUI(new Vector2(leftMargin + maxLabelWidth + 125.0f, nextY), importSettings, "lightmapped", null, "isStatic");

                CreateAllBoolsUI(new Vector2(leftMargin + maxLabelWidth + 175.0f, nextY), importSettings, "randomizeRotation");
                CreateAllBoolsUI(new Vector2(leftMargin + maxLabelWidth + 225.0f, nextY), importSettings, "preferLegacy");
                CreateAllLODsUI(new Vector2(leftMargin + maxLabelWidth + 275.0f, nextY), importSettings);

                // Reserve the space for the GUILayout scroll view.
                GUILayout.Space(25.0f);
                nextY += 25.0f;
            }

            var collidersOrConnectivityWhilePreferringLegacy = false;

            for (int i = 0; i < lxfml.groups.Length; i++)
            {
                var showGroup = group == null && model == null;              // When importing a new model, show all groups.
                showGroup |= model != null && importSettings.ContainsKey(i); // When reimporting an entire model, only show groups already in the existing model.
                showGroup |= group != null && i == group.number;             // When reimporting a model group, only show that group.
                if (showGroup)
                {
                    GUI.Label(new Rect(leftMargin, nextY, maxLabelWidth, 20.0f), lxfml.groups[i].name);

                    CreateBoolUI(new Vector2(leftMargin + maxLabelWidth + 15.0f, nextY), importSettings, "colliders", i, "connectivity", null);
                    CreateBoolUI(new Vector2(leftMargin + maxLabelWidth + 45.0f, nextY), importSettings, "connectivity", i, null, "colliders");

                    CreateBoolUI(new Vector2(leftMargin + maxLabelWidth + 95.0f, nextY), importSettings, "isStatic", i, "lightmapped", null);
                    CreateBoolUI(new Vector2(leftMargin + maxLabelWidth + 125.0f, nextY), importSettings, "lightmapped", i, null, "isStatic");

                    CreateBoolUI(new Vector2(leftMargin + maxLabelWidth + 175.0f, nextY), importSettings, "randomizeRotation", i);
                    CreateBoolUI(new Vector2(leftMargin + maxLabelWidth + 225.0f, nextY), importSettings, "preferLegacy", i);
                    CreateLODUI(new Vector2(leftMargin + maxLabelWidth + 275.0f, nextY), importSettings, i);

                    if ((importSettings[i].colliders || importSettings[i].connectivity) && importSettings[i].preferLegacy)
                    {
                        collidersOrConnectivityWhilePreferringLegacy = true;
                    }

                    // Reserve the space for the GUILayout scroll view.
                    GUILayout.Space(20.0f);
                    nextY += 20.0f;
                }
            }

            if (collidersOrConnectivityWhilePreferringLegacy)
            {
                EditorGUI.HelpBox(new Rect(leftMargin, nextY, position.width - leftMargin - 20.0f, 38.0f), "Legacy parts might not contain colliders or connectivity information.", MessageType.Warning);
                // Reserve the space for the GUILayout scroll view.
                GUILayout.Space(42.0f);
                nextY += 42.0f;
            }

            // Reserve the space for the GUILayout scroll view.
            GUILayout.Space(5.0f);
            nextY += 5.0f;

            // Only show pivot option when not reimporting.
            if (group == null && model == null)
            {
                GUI.Label(new Rect(leftMargin, nextY, maxLabelWidth, 20.0f), "Pivot");
                pivot = (Model.Pivot)EditorGUI.EnumPopup(new Rect(leftMargin + maxLabelWidth + 15.0f, nextY, 126.0f, 16.0f), pivot);

                // Reserve the space for the GUILayout scroll view.
                GUILayout.Space(25.0f);
                nextY += 25.0f;
            }

            // Create the right import/reimport button and handle the import/reimport based on the three cases:
            // - Reimport model
            // - Reimport model group
            // - Import model
            bool importPressed;

            if (model)
            {
                // ----------------------
                // Reimport entire model.
                // ----------------------
                importPressed = GUI.Button(new Rect(leftMargin, nextY, maxLabelWidth + 15.0f + 126.0f, 32.0f), "Reimport Model");

                if (importPressed)
                {
                    // Register undo.
                    Undo.RegisterFullObjectHierarchyUndo(model.gameObject, "Reimport");
                    model.pivot = pivot;

                    // Update the path if it is new.
                    if (filePath != null)
                    {
                        model.absoluteFilePath = filePath;
                        model.relativeFilePath = PathUtils.GetRelativePath(Directory.GetCurrentDirectory(), filePath);
                    }

                    ModelImporter.ReimportModel(lxfml, model, importSettings);

                    var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
                    if (prefabStage != null)
                    {
                        EditorSceneManager.MarkSceneDirty(prefabStage.scene);
                    }
                    SceneBrickBuilder.MarkSceneDirty();
                }
            }
            else if (group)
            {
                // ---------------------
                // Reimport model group.
                // ---------------------
                importPressed = GUI.Button(new Rect(leftMargin, nextY, maxLabelWidth + 15.0f + 126.0f, 32.0f), "Reimport Model Group");

                if (importPressed)
                {
                    // Register undo.
                    Undo.RegisterFullObjectHierarchyUndo(group.gameObject, "Reimport");

                    ModelImporter.ReimportModelGroup(lxfml, group, importSettings[group.number], true);

                    var prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
                    if (prefabStage != null)
                    {
                        EditorSceneManager.MarkSceneDirty(prefabStage.scene);
                    }
                    SceneBrickBuilder.MarkSceneDirty();
                }
            }
            else
            {
                // ----------------------
                // Import model.
                // ----------------------
                importPressed = GUI.Button(new Rect(leftMargin, nextY, maxLabelWidth + 15.0f + 126.0f, 32.0f), "Import Model");

                if (importPressed)
                {
                    model = ModelImporter.InstantiateModel(lxfml, filePath, pivot, importSettings).GetComponent <Model>();
                }

                var camera = SceneView.lastActiveSceneView.camera;
                if (camera && model)
                {
                    var          cameraRay = new Ray(camera.transform.position, camera.transform.forward);
                    PhysicsScene physicsScene;
                    if (PrefabStageUtility.GetCurrentPrefabStage() != null)
                    {
                        physicsScene = PrefabStageUtility.GetCurrentPrefabStage().scene.GetPhysicsScene();
                    }
                    else
                    {
                        physicsScene = PhysicsSceneExtensions.GetPhysicsScene(EditorSceneManager.GetActiveScene());
                    }

                    var bricksInModel = model.GetComponentsInChildren <Brick>();
                    var bricks        = new HashSet <Brick>(bricksInModel);
                    var sourceBrick   = bricks.First();

                    BrickBuildingUtility.AlignBricks(sourceBrick, bricks, BrickBuildingUtility.ComputeBounds(bricks), sourceBrick.transform.position, Vector3.zero, cameraRay,
                                                     new Plane(Vector3.up, Vector3.zero), 100.0f, out Vector3 offset, out Vector3 alignedOffset, out _, out _);

                    var offsetPosition = model.transform.position + alignedOffset;

                    model.transform.position = offsetPosition;

                    Selection.activeGameObject = model.gameObject;
                    Physics.SyncTransforms();
                }
                SceneBrickBuilder.MarkSceneDirty();
            }

            // Reserve the space for the GUILayout scroll view.
            GUILayout.Space(36.0f);
            nextY += 36.0f;

            // List tracked errors.
            foreach (var trackedError in trackedErrors)
            {
                EditorGUI.HelpBox(new Rect(leftMargin, nextY, maxLabelWidth + 340.0f, 38.0f), trackedError.Key, MessageType.Warning);
                // Reserve the space for the GUILayout scroll view.
                GUILayout.Space(42.0f);
                nextY += 42.0f;

                foreach (var id in trackedError.Value)
                {
                    GUI.Label(new Rect(leftMargin, nextY, maxLabelWidth + 340.0f, 16.0f), id);
                    // Reserve the space for the GUILayout scroll view.
                    GUILayout.Space(20.0f);
                    nextY += 20.0f;
                }
            }

            GUILayout.EndScrollView();

            if (importPressed)
            {
                this.Close();
            }
        }