示例#1
0
        /// <summary>
        /// For each solid in <see cref="carvers"/>, split intersecting solids in <see cref="carvees"/>
        /// by that solid. A carvee may be carved multiple times by the carver set.
        /// </summary>
        /// <param name="document">The document that's being edited</param>
        /// <param name="carvers">The list of objects to carve with</param>
        /// <param name="carvees">The list of objects that will be carved</param>
        /// <returns>An operation that will commit the changes.</returns>
        private static Transaction CarveObjects(MapDocument document, IEnumerable <Solid> carvers, IEnumerable <Solid> carvees)
        {
            // Create a copy of the carvee list which will be modified as the carve happens
            var carveSet = carvees.ToList();

            // Create a carve data to track changes before they are committed
            var data = new CarveData(carveSet);

            foreach (var carver in carvers)
            {
                var added   = new List <Solid>();
                var removed = new List <Solid>();

                // Carve all the candidates in the carve set
                // Since we're carving with only one object at this point, we can do all the carve set in one go
                // and do the add/remove operations at the end. This stops the carve result from potentially being re-carved somehow.
                foreach (var carvee in carveSet)
                {
                    var result = PerformCarve(document, carver, carvee, data);
                    if (result == null)
                    {
                        continue;
                    }

                    added.AddRange(result);
                    removed.Add(carvee);
                }

                // Update the carve set with the new changes
                carveSet.RemoveAll(removed.Contains);
                carveSet.AddRange(added);
            }

            // Return the result
            return(data.Transaction);
        }
示例#2
0
        /// <summary>
        /// Carve one solid into another and output the results into the provided lists.
        /// </summary>
        /// <param name="document">The document that's being edited</param>
        /// <param name="carver">The solid to carve with</param>
        /// <param name="carvee">The solid to carve into</param>
        /// <param name="data">The current carve data</param>
        /// <returns>The list of added solids if the carve was successful, null otherwise</returns>
        private static List <Solid> PerformCarve(MapDocument document, Solid carver, Solid carvee, CarveData data)
        {
            var split = false;
            var solid = carvee; // this reference will change as the carve continues
            var list  = new List <Solid>();

            foreach (var plane in carver.Faces.Select(x => x.Plane))
            {
                // Split solid by plane
                Solid back, front;
                try
                {
                    if (!solid.Split(document.Map.NumberGenerator, plane, out back, out front))
                    {
                        // If the solid is completely in front of the plane, then the solids don't overlap
                        if (back == null && front != null)
                        {
                            return(null);
                        }
                    }
                }
                catch
                {
                    // We're not too fussy about over-complicated carving, just get out if we've broken it.
                    break;
                }
                split = true;

                if (front != null)
                {
                    // Retain the front solid
                    if (solid.IsSelected)
                    {
                        front.IsSelected = true;
                    }
                    list.Add(front);
                }

                // If the back isn't valid, exit the carve as it cannot continue
                if (back == null || !back.IsValid())
                {
                    break;
                }

                // Use the back solid as the new clipping target
                if (solid.IsSelected)
                {
                    back.IsSelected = true;
                }
                solid = back;
            }

            if (!split)
            {
                return(null);
            }

            // Update the carve data
            foreach (var s in list)
            {
                data.Attach(carvee, s);
            }
            data.Detatch(carvee);

            return(list);
        }