public MyCsgShapeExcludedSphere(VRageMath.Vector3 translation, float radius, float exclusionRadius, float halfDeviation = 0, float deviationFrequency = 0, float detailFrequency = 0)
        {
            m_translation        = translation;
            m_radius             = radius;
            m_halfDeviation      = halfDeviation;
            m_deviationFrequency = deviationFrequency;
            m_detailFrequency    = detailFrequency;


            m_sphere          = new MyCsgSphere(translation, radius, halfDeviation, deviationFrequency, detailFrequency);
            m_exclusionSphere = new MyCsgSphere(translation, exclusionRadius, halfDeviation, deviationFrequency, detailFrequency);
        }
        public MyCsgShapeExcludedSphere(VRageMath.Vector3 translation, float radius,float exclusionRadius, float halfDeviation = 0, float deviationFrequency = 0, float detailFrequency = 0)
        {
            m_translation = translation;
            m_radius = radius;
            m_halfDeviation = halfDeviation;
            m_deviationFrequency = deviationFrequency;
            m_detailFrequency = detailFrequency;


            m_sphere = new MyCsgSphere(translation, radius, halfDeviation, deviationFrequency, detailFrequency);
            m_exclusionSphere = new MyCsgSphere(translation, exclusionRadius, halfDeviation, deviationFrequency, detailFrequency); 
        }
        private static void Generator(int version, int seed, float size, out MyCompositeShapeGeneratedData data)
        {
            var random = MyRandom.Instance;
            using (var stateToken = random.PushSeed(seed))
            {
                data = new MyCompositeShapeGeneratedData();
                data.FilledShapes = new MyCsgShapeBase[2];
                data.RemovedShapes = new MyCsgShapeBase[2];
                data.MacroModule = new MySimplexFast(seed: seed, frequency: 7f / size);
                switch (random.Next() & 0x1)
                {
                    case 0:
                        data.DetailModule = new MyRidgedMultifractalFast(
                            seed: seed,
                            quality: MyNoiseQuality.Low,
                            frequency: random.NextFloat() * 0.09f + 0.11f,
                            layerCount: 1);
                        break;

                    case 1:
                    default:
                        data.DetailModule = new MyBillowFast(
                            seed: seed,
                            quality: MyNoiseQuality.Low,
                            frequency: random.NextFloat() * 0.07f + 0.13f,
                            layerCount: 1);
                        break;
                }

                float halfSize = size * 0.5f;
                float storageSize = VRageMath.MathHelper.GetNearestBiggerPowerOfTwo(size);
                float halfStorageSize = storageSize * 0.5f;
                float storageOffset = halfStorageSize - halfSize;

                MyCsgShapeBase primaryShape;
                { // determine primary shape
                    var primaryType = random.Next() % 3;
                    switch (primaryType)
                    {
                        case 0: //ShapeType.Torus
                            {
                                var secondaryRadius = (random.NextFloat() * 0.05f + 0.1f) * size;
                                var torus = new MyCsgTorus(
                                    translation: new Vector3(halfStorageSize),
                                    invRotation: CreateRandomRotation(random),
                                    primaryRadius: (random.NextFloat() * 0.1f + 0.2f) * size,
                                    secondaryRadius: secondaryRadius,
                                    secondaryHalfDeviation: (random.NextFloat() * 0.4f + 0.4f) * secondaryRadius,
                                    deviationFrequency: random.NextFloat() * 0.8f + 0.2f,
                                    detailFrequency: random.NextFloat() * 0.6f + 0.4f);
                                primaryShape = torus;
                            }
                            break;

                        case 1: //ShapeType.Sphere
                        default:
                            {
                                var sphere = new MyCsgSphere(
                                    translation: new Vector3(halfStorageSize),
                                    radius: (random.NextFloat() * 0.1f + 0.35f) * size,
                                    halfDeviation: (random.NextFloat() * 0.05f + 0.05f) * size + 1f,
                                    deviationFrequency: random.NextFloat() * 0.8f + 0.2f,
                                    detailFrequency: random.NextFloat() * 0.6f + 0.4f);
                                primaryShape = sphere;
                            }
                            break;
                    }
                }

                { // add some additional shapes
                    int filledShapeCount = 0;
                    data.FilledShapes[filledShapeCount++] = primaryShape;
                    while (filledShapeCount < data.FilledShapes.Length)
                    {
                        var fromBorders = size * (random.NextFloat() * 0.2f + 0.1f) + 2f;
                        var fromBorders2 = 2f * fromBorders;
                        var sizeMinusFromBorders2 = size - fromBorders2;
                        var shapeType = random.Next() % 3;
                        switch (shapeType)
                        {
                            case 0: //ShapeType.Sphere
                                {
                                    Vector3 center = CreateRandomPointOnBox(random, sizeMinusFromBorders2) + fromBorders;
                                    float radius = fromBorders * (random.NextFloat() * 0.4f + 0.35f);

                                    MyCsgSphere sphere = new MyCsgSphere(
                                        translation: center + storageOffset,
                                        radius: radius,
                                        halfDeviation: radius * (random.NextFloat() * 0.1f + 0.1f),
                                        deviationFrequency: random.NextFloat() * 0.8f + 0.2f,
                                        detailFrequency: random.NextFloat() * 0.6f + 0.4f);

                                    data.FilledShapes[filledShapeCount++] = sphere;
                                }
                                break;

                            case 1: //ShapeType.Capsule
                                {
                                    var start = CreateRandomPointOnBox(random, sizeMinusFromBorders2) + fromBorders;
                                    var end = new Vector3(size) - start;
                                    if ((random.Next() % 2) == 0) MyUtils.Swap(ref start.X, ref end.X);
                                    if ((random.Next() % 2) == 0) MyUtils.Swap(ref start.Y, ref end.Y);
                                    if ((random.Next() % 2) == 0) MyUtils.Swap(ref start.Z, ref end.Z);
                                    float radius = (random.NextFloat() * 0.25f + 0.5f) * fromBorders;

                                    MyCsgCapsule capsule = new MyCsgCapsule(
                                        pointA: start + storageOffset,
                                        pointB: end + storageOffset,
                                        radius: radius,
                                        halfDeviation: (random.NextFloat() * 0.25f + 0.5f) * radius,
                                        deviationFrequency: (random.NextFloat() * 0.4f + 0.4f),
                                        detailFrequency: (random.NextFloat() * 0.6f + 0.4f));

                                    data.FilledShapes[filledShapeCount++] = capsule;
                                }
                                break;

                            case 2: //ShapeType.Torus
                                {
                                    Vector3 center = CreateRandomPointInBox(random, sizeMinusFromBorders2) + fromBorders;
                                    var rotation = CreateRandomRotation(random);
                                    var borderDistance = ComputeBoxSideDistance(center, size);
                                    var secondaryRadius = (random.NextFloat() * 0.15f + 0.1f) * borderDistance;

                                    var torus = new MyCsgTorus(
                                        translation: center + storageOffset,
                                        invRotation: rotation,
                                        primaryRadius: (random.NextFloat() * 0.2f + 0.5f) * borderDistance,
                                        secondaryRadius: secondaryRadius,
                                        secondaryHalfDeviation: (random.NextFloat() * 0.25f + 0.2f) * secondaryRadius,
                                        deviationFrequency: random.NextFloat() * 0.8f + 0.2f,
                                        detailFrequency: random.NextFloat() * 0.6f + 0.4f);

                                    data.FilledShapes[filledShapeCount++] = torus;
                                }
                                break;
                        }
                    }
                }

                { // make some holes
                    int removedShapesCount = 0;

                    while (removedShapesCount < data.RemovedShapes.Length)
                    {
                        var fromBorders = size * (random.NextFloat() * 0.2f + 0.1f) + 2f;
                        var fromBorders2 = 2f * fromBorders;
                        var sizeMinusFromBorders2 = size - fromBorders2;
                        var shapeType = random.Next() % 7;
                        switch (shapeType)
                        {
                            // Sphere
                            case 0:
                                {
                                    Vector3 center = CreateRandomPointInBox(random, sizeMinusFromBorders2) + fromBorders;

                                    float borderDistance = ComputeBoxSideDistance(center, size);
                                    float radius = (random.NextFloat() * 0.4f + 0.3f) * borderDistance;
                                    MyCsgSphere sphere = new MyCsgSphere(
                                        translation: center + storageOffset,
                                        radius: radius,
                                        halfDeviation: (random.NextFloat() * 0.3f + 0.35f) * radius,
                                        deviationFrequency: (random.NextFloat() * 0.8f + 0.2f),
                                        detailFrequency: (random.NextFloat() * 0.6f + 0.4f));

                                    data.RemovedShapes[removedShapesCount++] = sphere;
                                    break;
                                }

                            // Torus
                            case 1:
                            case 2:
                            case 3:
                                {
                                    Vector3 center = CreateRandomPointInBox(random, sizeMinusFromBorders2) + fromBorders;
                                    var rotation = CreateRandomRotation(random);
                                    var borderDistance = ComputeBoxSideDistance(center, size);
                                    var secondaryRadius = (random.NextFloat() * 0.15f + 0.1f) * borderDistance;

                                    var torus = new MyCsgTorus(
                                        translation: center + storageOffset,
                                        invRotation: rotation,
                                        primaryRadius: (random.NextFloat() * 0.2f + 0.5f) * borderDistance,
                                        secondaryRadius: secondaryRadius,
                                        secondaryHalfDeviation: (random.NextFloat() * 0.25f + 0.2f) * secondaryRadius,
                                        deviationFrequency: random.NextFloat() * 0.8f + 0.2f,
                                        detailFrequency: random.NextFloat() * 0.6f + 0.4f);

                                    data.RemovedShapes[removedShapesCount++] = torus;
                                }
                                break;

                            // Capsule
                            default:
                                {
                                    var start = CreateRandomPointOnBox(random, sizeMinusFromBorders2) + fromBorders;
                                    var end = new Vector3(size) - start;
                                    if ((random.Next() % 2) == 0) MyUtils.Swap(ref start.X, ref end.X);
                                    if ((random.Next() % 2) == 0) MyUtils.Swap(ref start.Y, ref end.Y);
                                    if ((random.Next() % 2) == 0) MyUtils.Swap(ref start.Z, ref end.Z);
                                    float radius = (random.NextFloat() * 0.25f + 0.5f) * fromBorders;

                                    MyCsgCapsule capsule = new MyCsgCapsule(
                                        pointA: start + storageOffset,
                                        pointB: end + storageOffset,
                                        radius: radius,
                                        halfDeviation: (random.NextFloat() * 0.25f + 0.5f) * radius,
                                        deviationFrequency: random.NextFloat() * 0.4f + 0.4f,
                                        detailFrequency: random.NextFloat() * 0.6f + 0.4f);
                                    
                                    data.RemovedShapes[removedShapesCount++] = capsule;
                                }
                                break;
                        }
                    }
                }

                { // generating materials
                    // What to do when we (or mods) change the number of materials? Same seed will then produce different results.
                    FillMaterials(version);

                    Action<List<MyVoxelMaterialDefinition>> shuffleMaterials = (list) =>
                    {
                        int n = list.Count;
                        while (n > 1)
                        {
                            int k = (int)random.Next() % n;
                            n--;
                            var value = list[k];
                            list[k] = list[n];
                            list[n] = value;
                        }
                    };
                    shuffleMaterials(m_depositMaterials);

                    if (m_surfaceMaterials.Count == 0)
                    {
                        if (m_depositMaterials.Count == 0)
                        {
                            data.DefaultMaterial = m_coreMaterials[(int)random.Next() % m_coreMaterials.Count];
                        }
                        else
                        {
                            data.DefaultMaterial = m_depositMaterials[(int)random.Next() % m_depositMaterials.Count];
                        }
                    }
                    else
                    {
                        data.DefaultMaterial = m_surfaceMaterials[(int)random.Next() % m_surfaceMaterials.Count];
                    }

                    if (false)
                    {
                        data.Deposits = new MyCompositeShapeOreDeposit[data.FilledShapes.Length];
                        int currentMaterial = 0;
                        int depositCount = 0;

                        data.Deposits[depositCount] = new MyCompositeShapeOreDeposit(data.FilledShapes[depositCount].DeepCopy(), m_coreMaterials[(int)random.Next() % m_coreMaterials.Count]);
                        data.Deposits[depositCount].Shape.ShrinkTo(random.NextFloat() * 0.15f + 0.6f);
                        ++depositCount;
                        while (depositCount < data.FilledShapes.Length)
                        {
                            data.Deposits[depositCount] = new MyCompositeShapeOreDeposit(data.FilledShapes[depositCount].DeepCopy(), m_depositMaterials[currentMaterial++]);
                            data.Deposits[depositCount].Shape.ShrinkTo(random.NextFloat() * 0.15f + 0.6f);
                            ++depositCount;
                            if (currentMaterial == m_depositMaterials.Count)
                            {
                                currentMaterial = 0;
                                shuffleMaterials(m_depositMaterials);
                            }
                        }
                    }
                    else
                    {
                        int depositCount = Math.Max((int)Math.Log(size), data.FilledShapes.Length);
                        data.Deposits = new MyCompositeShapeOreDeposit[depositCount];

                        var depositSize = size / 10f;

                        int currentMaterial = 0;
                        for (int i = 0; i < data.FilledShapes.Length; ++i)
                        {
                            MyVoxelMaterialDefinition material;
                            if (i == 0)
                            {
                                if (m_coreMaterials.Count == 0)
                                {
                                    if (m_depositMaterials.Count == 0)
                                    {
                                        material = m_surfaceMaterials[(int)random.Next() % m_surfaceMaterials.Count];
                                    }
                                    else
                                    {
                                        material = m_depositMaterials[currentMaterial++];
                                    }
                                }
                                else
                                {
                                    material = m_coreMaterials[(int)random.Next() % m_coreMaterials.Count];
                                }
                            }
                            else
                            {
                                if (m_depositMaterials.Count == 0)
                                {
                                    material = m_surfaceMaterials[(int)random.Next() % m_surfaceMaterials.Count];
                                }
                                else
                                {
                                    material = m_depositMaterials[currentMaterial++];
                                }
                            }
                            data.Deposits[i] = new MyCompositeShapeOreDeposit(data.FilledShapes[i].DeepCopy(), material);
                            data.Deposits[i].Shape.ShrinkTo(random.NextFloat() * 0.15f + 0.6f);
                            if (currentMaterial == m_depositMaterials.Count)
                            {
                                currentMaterial = 0;
                                shuffleMaterials(m_depositMaterials);
                            }
                        }
                        for (int i = data.FilledShapes.Length; i < depositCount; ++i)
                        {
                            var center = CreateRandomPointInBox(random, size * 0.7f) + storageOffset + size * 0.15f;
                            var radius = random.NextFloat() * depositSize + 8f;
                            random.NextFloat();random.NextFloat();//backwards compatibility
                            MyCsgShapeBase shape = new MyCsgSphere(center, radius);

                            MyVoxelMaterialDefinition material;
                            if (m_depositMaterials.Count == 0)
                            {
                                material = m_surfaceMaterials[currentMaterial++];
                            }
                            else
                            {
                                material = m_depositMaterials[currentMaterial++];
                            }

                            data.Deposits[i] = new MyCompositeShapeOreDeposit(shape, material);

                            if (m_depositMaterials.Count == 0)
                            {
                                if (currentMaterial == m_surfaceMaterials.Count)
                                {
                                    currentMaterial = 0;
                                    shuffleMaterials(m_surfaceMaterials);
                                }
                            }
                            else
                            {

                                if (currentMaterial == m_depositMaterials.Count)
                                {
                                    currentMaterial = 0;
                                    shuffleMaterials(m_depositMaterials);
                                }
                            }
                        }
                    }

                    m_surfaceMaterials.Clear();
                    m_coreMaterials.Clear();
                    m_depositMaterials.Clear();
                }
            }
        }