예제 #1
0
        /// <summary>
        /// Wrap input geometry into module cages.
        /// </summary>
        /// <param name="DA">The DA object can be used to retrieve data from
        ///     input parameters and to store data in output parameters.</param>
        protected override void SolveInstance(IGH_DataAccess DA)
        {
            var geometryRaw = new List <IGH_GeometricGoo>();
            var module      = new Module();
            var basePlane   = new Plane();

            if (!DA.GetDataList(0, geometryRaw))
            {
                return;
            }

            if (!DA.GetData(1, ref module))
            {
                return;
            }

            if (!DA.GetData(2, ref basePlane))
            {
                return;
            }

            if (module == null || !module.IsValid)
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Error, "Module is null or invalid.");
                return;
            }

            // Transform the geometry to be oriented to world XYZ fore easier scanning
            var geometryTransform = Transform.PlaneToPlane(basePlane, Plane.WorldXY);
            var geometryClean     = geometryRaw
                                    .Select(goo => GH_Convert.ToGeometryBase(goo))
                                    .Where(geo => geo != null)
                                    .Select(geo => {
                var transformedGeometry = geo.Duplicate();
                transformedGeometry.Transform(geometryTransform);
                return(transformedGeometry);
            }).ToList();

            if (!geometryClean.Any())
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning,
                                  "Failed to collect any valid geometry to scan.");
                return;
            }

            var moduleGeometry = module.Geometry
                                 .Concat(module.ReferencedGeometry);

            if (!moduleGeometry.Any())
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning,
                                  "Module \"" + module.Name + "\" contains " +
                                  "no geometry and therefore will be skipped.");
                return;
            }

            var moduleGeometryBBoxes = moduleGeometry.Select(geo => geo.GetBoundingBox(true));

            var bBoxUnionModule = BoundingBox.Empty;

            bBoxUnionModule.Union(module.Pivot.Origin);
            foreach (var moduleBBox in moduleGeometryBBoxes)
            {
                bBoxUnionModule.Union(moduleBBox);
            }
            var moduleDimensionSafetyBuffer = new Point3i(
                (int)Math.Ceiling(bBoxUnionModule.Diagonal.X / module.PartDiagonal.X) + 1,
                (int)Math.Ceiling(bBoxUnionModule.Diagonal.Y / module.PartDiagonal.Y) + 1,
                (int)Math.Ceiling(bBoxUnionModule.Diagonal.Z / module.PartDiagonal.Z) + 1);

            var geometryBBoxes    = geometryClean.Select(geo => geo.GetBoundingBox(true)).ToList();
            var bBoxUnionGeometry = BoundingBox.Empty;

            foreach (var bBox in geometryBBoxes)
            {
                bBoxUnionGeometry.Union(bBox);
            }

            var slots = new List <Slot>();

            for (int z = (int)Math.Floor(bBoxUnionGeometry.Min.Z / module.PartDiagonal.Z) - moduleDimensionSafetyBuffer.Z;
                 z < Math.Ceiling(bBoxUnionGeometry.Max.Z / module.PartDiagonal.Z) + moduleDimensionSafetyBuffer.Z;
                 z++)
            {
                for (int y = (int)Math.Floor(bBoxUnionGeometry.Min.Y / module.PartDiagonal.Y) - moduleDimensionSafetyBuffer.Y;
                     y < Math.Ceiling(bBoxUnionGeometry.Max.Y / module.PartDiagonal.Y) + moduleDimensionSafetyBuffer.Y;
                     y++)
                {
                    for (int x = (int)Math.Floor(bBoxUnionGeometry.Min.X / module.PartDiagonal.X) - moduleDimensionSafetyBuffer.X;
                         x < Math.Ceiling(bBoxUnionGeometry.Max.X / module.PartDiagonal.X) + moduleDimensionSafetyBuffer.X;
                         x++)
                    {
                        var currentRelativePosition = new Point3i(x, y, z);
                        var currentPivot            = Plane.WorldXY;
                        currentPivot.Origin = currentRelativePosition.ToCartesian(Plane.WorldXY, module.PartDiagonal);

                        var transformModuleToCurrentPivot      = Transform.PlaneToPlane(module.Pivot, currentPivot);
                        var moduleGeometryBBoxesAtCurrentPivot = moduleGeometryBBoxes.Select(bBox => {
                            var transformedBBox = bBox;
                            transformedBBox.Transform(transformModuleToCurrentPivot);
                            return(transformedBBox);
                        });

                        var indicesOfSimilarBBoxes = moduleGeometryBBoxesAtCurrentPivot.Select(moduleGeometryBBox =>
                                                                                               geometryBBoxes.Select((geometryBBox, index) => {
                            var moduleCorners   = moduleGeometryBBox.GetCorners().ToList();
                            var geometryCorners = geometryBBox.GetCorners().ToList();
                            moduleCorners.Sort();
                            geometryCorners.Sort();
                            if (Enumerable.SequenceEqual(moduleCorners, geometryCorners))
                            {
                                return(index);
                            }
                            else
                            {
                                return(-1);
                            }
                        }).Where(index => index != -1)
                                                                                               );

                        // If any module geometry doesn't have a bbox similar to any geometry, then early continue
                        if (!indicesOfSimilarBBoxes.All(similarBBoxes => similarBBoxes.Any()))
                        {
                            continue;
                        }

                        // Heavy calculations

                        var transformedModuleGeometry = moduleGeometry.Select(geo => {
                            var transformedGeometry = geo.Duplicate();
                            transformedGeometry.Transform(transformModuleToCurrentPivot);
                            return(transformedGeometry);
                        });

                        var geometriesToCheck = indicesOfSimilarBBoxes.Select(indices => indices.Select(index => geometryClean[index]));

                        var geometryEqualityPattern = transformedModuleGeometry
                                                      .Zip(geometriesToCheck, (current, others) => others.Any(other =>
                                                                                                              // TODO: when the original geometry is moved, the meshes become unequal
                                                                                                              // TODO: replace with visual similarity check (pull random points to geometry)
                                                                                                              // TODO: check if the two are of the same type first
                                                                                                              GeometryBase.GeometryEquals(current, other)
                                                                                                              ));

                        if (geometryEqualityPattern.All(equal => equal))
                        {
                            var firstModulePartRelativeCenter = module.PartCenters[0];
                            var modulePartsRelativeCentersRelativeToModulePivot = module.PartCenters.Select(center => center - firstModulePartRelativeCenter);

                            var currentModuleSlots = modulePartsRelativeCentersRelativeToModulePivot
                                                     .Zip(
                                module.PartNames,
                                (partCenter, partName) => new Slot(basePlane,
                                                                   currentRelativePosition + partCenter,
                                                                   module.PartDiagonal,
                                                                   false,
                                                                   new List <string>()
                            {
                                module.Name
                            },
                                                                   new List <string>()
                            {
                                partName
                            },
                                                                   0));
                            slots.AddRange(currentModuleSlots);
                        }
                    }
                }
            }

            if (!Slot.AreSlotLocationsUnique(slots))
            {
                AddRuntimeMessage(GH_RuntimeMessageLevel.Warning, "Slot centers are not unique.");
            }

            DA.SetDataList(0, slots);
        }