Beispiel #1
0
        public static void CreatePreviewObjects(Component_Scene scene, Component_Surface surface)
        {
            DestroyPreviewObjects(scene);

            var center = Vector3.Zero;

            //!!!!среднее от всех групп
            double minDistanceBetweenObjects;
            {
                var groups = surface.GetComponents <Component_SurfaceGroupOfElements>();
                if (groups.Length != 0)
                {
                    minDistanceBetweenObjects = 0;
                    foreach (var group in groups)
                    {
                        minDistanceBetweenObjects += group.MinDistanceBetweenObjects;
                    }
                    minDistanceBetweenObjects /= groups.Length;
                }
                else
                {
                    minDistanceBetweenObjects = 1;
                }
            }

            //!!!!
            var toolRadius   = minDistanceBetweenObjects * 5; // CreateObjectsBrushRadius;
            var toolStrength = 1.0;                           // CreateObjectsBrushStrength;
            var toolHardness = 0;                             // CreateObjectsBrushHardness;
            var random       = new Random(0);

            double GetHardnessFactor(double length)
            {
                if (length == 0 || length <= toolHardness * toolRadius)
                {
                    return(1);
                }
                else
                {
                    double c;
                    if (toolRadius - toolRadius * toolHardness != 0)
                    {
                        c = (length - toolRadius * toolHardness) / (toolRadius - toolRadius * toolHardness);
                    }
                    else
                    {
                        c = 0;
                    }
                    return((float)Math.Cos(Math.PI / 2 * c));
                }
            }

            //calculate object count
            int count;
            {
                var toolSquare = Math.PI * toolRadius * toolRadius;

                double radius       = minDistanceBetweenObjects / 2;
                double objectSquare = Math.PI * radius * radius;
                if (objectSquare < 0.1)
                {
                    objectSquare = 0.1;
                }

                double maxCount = toolSquare / objectSquare;
                maxCount /= 10;

                count = (int)(toolStrength * (double)maxCount);
                count = Math.Max(count, 1);


                count *= 20;
            }

            var data = new List <Component_GroupOfObjects.Object>(count);

            //create point container to check by MinDistanceBetweenObjects
            PointContainer3D pointContainerFindFreePlace;

            {
                double minDistanceBetweenObjectsMax = 0;
                foreach (var group in surface.GetComponents <Component_SurfaceGroupOfElements>())
                {
                    minDistanceBetweenObjectsMax = Math.Max(minDistanceBetweenObjectsMax, group.MinDistanceBetweenObjects);
                }

                var bounds = new Bounds(center);
                bounds.Expand(toolRadius + minDistanceBetweenObjectsMax);
                pointContainerFindFreePlace = new PointContainer3D(bounds, 100);
            }

            for (int n = 0; n < count; n++)
            {
                surface.GetRandomVariation(new Component_Surface.GetRandomVariationOptions(), random, out var groupIndex, out var elementIndex, out var positionZ, out var rotation, out var scale);
                var surfaceGroup = surface.GetGroup(groupIndex);

                Vector3?position = null;

                int counter = 0;
                while (counter < 20)
                {
                    var offset = new Vector2(random.Next(toolRadius * 2) - toolRadius, random.Next(toolRadius * 2) - toolRadius);

                    //check by radius and by hardness
                    var length = offset.Length();
                    if (length <= toolRadius && random.NextDouble() <= GetHardnessFactor(length))
                    {
                        var position2 = center.ToVector2() + offset;

                        //var result = Component_Scene_Utility.CalculateObjectPositionZ( Scene, toGroupOfObjects, center.Z, position2, destinationCachedBaseObjects );
                        //if( result.found )
                        //{

                        var p = new Vector3(position2, 0);                          // result.positionZ );

                        //check by MinDistanceBetweenObjects
                        if (surfaceGroup == null || !pointContainerFindFreePlace.Contains(new Sphere(p, surfaceGroup.MinDistanceBetweenObjects)))
                        {
                            //found place to create
                            position = p;
                            break;
                        }

                        //}
                    }

                    counter++;
                }

                if (position != null)
                {
                    var objPosition = position.Value + new Vector3(0, 0, positionZ);
                    var objRotation = rotation;
                    var objScale    = scale;


                    var surfaceElement = surfaceGroup.GetElement(elementIndex);

                    var surfaceElementMesh = surfaceElement as Component_SurfaceElement_Mesh;
                    if (surfaceElementMesh != null)
                    {
                        var meshInSpace = scene.CreateComponent <Component_MeshInSpace>(enabled: false);
                        meshInSpace.Transform = new Transform(objPosition, objRotation, objScale);

                        //!!!!так копировать?
                        meshInSpace.Mesh = surfaceElementMesh.Mesh;
                        if (meshInSpace.Mesh.Value == null)
                        {
                            meshInSpace.Mesh = ResourceUtility.MeshInvalid;
                        }

                        //!!!!так копировать?
                        if (surfaceElementMesh.ReplaceMaterial.ReferenceSpecified)
                        {
                            meshInSpace.ReplaceMaterial = surfaceElementMesh.ReplaceMaterial;
                        }

                        meshInSpace.Enabled = true;
                    }

                    //add to point container
                    pointContainerFindFreePlace.Add(ref objPosition);
                }
            }
        }
        Component_GroupOfObjects.Object[] UpdateOutputDefault(Component_Surface surface, Component_GroupOfObjects groupOfObjects)
        {
            var pointPositions  = GetPointPositions();
            var pointPositions2 = pointPositions.Select(a => a.ToVector2()).ToArray();
            var pointBounds     = GetPointPositionsBounds();

            var lines = new List <Line2>();

            for (int n = 0; n < pointPositions2.Length; n++)
            {
                lines.Add(new Line2(pointPositions2[n], pointPositions2[(n + 1) % pointPositions2.Length]));
            }

            var random = new Random(RandomSeed.Value);

            double GetFadeFactor(Vector2 point)
            {
                var minLength = double.MaxValue;

                foreach (var line in lines)
                {
                    var d = Math.Min((line.Start - point).Length(), (line.End - point).Length());

                    var projected = MathAlgorithms.ProjectPointToLine(line.Start, line.End, point);

                    Rectangle b = new Rectangle(line.Start);
                    b.Add(line.End);
                    if (b.Contains(projected))
                    {
                        var d2 = (projected - point).Length();
                        if (d2 < d)
                        {
                            d = d2;
                        }
                    }

                    if (d < minLength)
                    {
                        minLength = d;
                    }
                }

                if (minLength >= FadeLength)
                {
                    return(1);
                }
                return(minLength / FadeLength);
            }

            if (pointPositions.Length >= 3)
            {
                //calculate object count
                int count;
                {
                    double polygonArea;
                    {
                        var points = new List <Vector2>(pointPositions2);
                        points.Add(points[0]);

                        polygonArea = Math.Abs(points.Take(points.Count - 1)
                                               .Select((p, i) => (points[i + 1].X - p.X) * (points[i + 1].Y + p.Y))
                                               .Sum() / 2);
                    }

                    //!!!!среднее от всех групп
                    double minDistanceBetweenObjects;
                    {
                        var groups = surface.GetComponents <Component_SurfaceGroupOfElements>();
                        if (groups.Length != 0)
                        {
                            minDistanceBetweenObjects = 0;
                            foreach (var group in groups)
                            {
                                minDistanceBetweenObjects += group.MinDistanceBetweenObjects;
                            }
                            minDistanceBetweenObjects /= groups.Length;
                        }
                        else
                        {
                            minDistanceBetweenObjects = 1;
                        }
                    }

                    double radius     = minDistanceBetweenObjects / 2;
                    double objectArea = Math.PI * radius * radius;
                    if (objectArea < 0.1)
                    {
                        objectArea = 0.1;
                    }

                    double maxCount = polygonArea / objectArea;

                    count = (int)(Strength * (double)maxCount);
                    count = Math.Max(count, 0);
                }

                var data = new List <Component_GroupOfObjects.Object>(count);

                var scene = groupOfObjects.FindParent <Component_Scene>();
                if (scene != null)
                {
                    var destinationCachedBaseObjects = groupOfObjects.GetBaseObjects();

                    var pointContainerFindFreePlace = new PointContainer3D(pointBounds, 100);

                    for (int n = 0; n < count; n++)
                    {
                        surface.GetRandomVariation(new Component_Surface.GetRandomVariationOptions(), random, out var groupIndex, out var elementIndex, out var positionZ, out var rotation, out var scale);
                        var surfaceGroup = surface.GetGroup(groupIndex);

                        Vector3?position = null;

                        int counter = 0;
                        while (counter < 20)
                        {
                            Vector2 position2 = Vector2.Zero;
                            position2.X = MathEx.Lerp(pointBounds.Minimum.X, pointBounds.Maximum.X, random.NextFloat());
                            position2.Y = MathEx.Lerp(pointBounds.Minimum.Y, pointBounds.Maximum.Y, random.NextFloat());

                            if (MathAlgorithms.IsPointInPolygon(pointPositions2, position2))
                            {
                                double factor = 1;
                                if (FadeLength > 0)
                                {
                                    factor = GetFadeFactor(position2);
                                }

                                if (factor >= 1 || random.NextDouble() <= factor)
                                {
                                    var result = Component_Scene_Utility.CalculateObjectPositionZ(scene, groupOfObjects, pointBounds.GetCenter().Z, position2, destinationCachedBaseObjects);
                                    if (result.found || destinationCachedBaseObjects.Count == 0)
                                    {
                                        var p = new Vector3(position2, destinationCachedBaseObjects.Count != 0 ? result.positionZ : pointBounds.GetCenter().Z);

                                        //check by MinDistanceBetweenObjects
                                        if (surfaceGroup == null || !pointContainerFindFreePlace.Contains(new Sphere(p, surfaceGroup.MinDistanceBetweenObjects)))
                                        {
                                            //found place to create
                                            position = p;
                                            break;
                                        }
                                    }
                                }
                            }

                            counter++;
                        }

                        if (position != null)
                        {
                            var obj = new Component_GroupOfObjects.Object();
                            obj.Element          = 0;                   // (ushort)element.Index.Value;
                            obj.VariationGroup   = groupIndex;
                            obj.VariationElement = elementIndex;
                            obj.Flags            = Component_GroupOfObjects.Object.FlagsEnum.Enabled | Component_GroupOfObjects.Object.FlagsEnum.Visible;
                            obj.Position         = position.Value + new Vector3(0, 0, positionZ);
                            obj.Rotation         = rotation;
                            obj.Scale            = scale;
                            obj.Color            = ColorValue.One;
                            data.Add(obj);

                            //add to point container
                            pointContainerFindFreePlace.Add(ref obj.Position);
                        }
                    }
                }

                return(data.ToArray());
            }
            else
            {
                return(new Component_GroupOfObjects.Object[0]);
            }
        }