예제 #1
0
        void SwapSimulatedDatas()
        {
            var temp = m_finishedData;

            m_finishedData  = m_simulatedData;
            m_simulatedData = temp;
        }
예제 #2
0
 private void AddNeighbours(GridSimulationData simData)
 {
     using (Stats.Timing.Measure("SI - AddNeighbours", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag))
     {
         foreach (var node in simData.All)
         {
             foreach (var offset in Offsets)
             {
                 Node neighbour;
                 if (simData.All.TryGetValue(node.Value.Pos + offset, out neighbour))
                 {
                     node.Value.Neighbours.Add(neighbour);
                 }
             }
         }
     }
 }
예제 #3
0
        private void FindAndCaculateFromAdvancedStatic(GridSimulationData simData)
        {
            // Instead of using uniform distribution of support between all fixed nodes, calculate non-uniform distribution based on vectors for few closest nodes
            // Use this distribution when setting support weight and transferring mass
            // SupportingWeights: x * support
            // ? TransferMass: x * numStaticBlocksForCurrentDynamicBlock * TransferMass

            int keepLookingDistance = (int)ClosestDistanceThreshold; // How far keep looking when closest static block is found

            simData.Queue.Clear();

            // Set initial distance to max for all dynamic
            foreach (var dyn in simData.DynamicBlocks)
            {
                dyn.Distance = int.MaxValue;
            }

            // Wide search from all static blocks
            foreach (var stat in simData.StaticBlocks)
            {
                stat.Distance = 0;
                var path = new PathInfo()
                {
                    EndNode = stat, StartNode = stat, Distance = 0, DirectionRatio = 1
                };
#if ENHANCED_DEBUG
                path.PathNodes.Add(stat);
#endif
                simData.Queue.Enqueue(path);
            }

            while (simData.Queue.Count > 0)
            {
                var path = simData.Queue.Dequeue();
                foreach (var neighbour in path.EndNode.Neighbours)
                {
                    if (neighbour.IsStatic)
                    {
                        continue;
                    }

                    PathInfo neighbourPath;
                    if (!neighbour.Paths.TryGetValue(path.StartNode, out neighbourPath))
                    {
                        if ((path.Distance - keepLookingDistance) <= neighbour.Distance)
                        {
                            neighbour.Distance = Math.Min(neighbour.Distance, path.Distance);

                            neighbourPath           = new PathInfo();
                            neighbourPath.Distance  = path.Distance + 1;
                            neighbourPath.StartNode = path.StartNode;
                            neighbourPath.EndNode   = neighbour;
#if ENHANCED_DEBUG
                            neighbourPath.PathNodes = path.PathNodes.ToList();
                            neighbourPath.PathNodes.Add(neighbour);
#endif
                            neighbourPath.Parents.Add(path);
                            float t = neighbour.PhysicalMaterial.HorisontalTransmissionMultiplier * path.EndNode.PhysicalMaterial.HorisontalTransmissionMultiplier;

                            float massRatio = MathHelper.Clamp(path.EndNode.Mass / (neighbour.Mass + path.EndNode.Mass), 0, 1);

                            t *= neighbour.Mass * massRatio; //Horisontal transmission is very low on weak objects (floor, roof). Should be correctly get from mount point area
                            float[] horisontalTransmission = new float[] { t, 1, t };

                            int component = ((Vector3D)(neighbour.Pos - path.EndNode.Pos)).AbsMaxComponent();
                            neighbourPath.DirectionRatio = path.DirectionRatio * DirectionRatios[component] * horisontalTransmission[component];
                            neighbour.Paths.Add(path.StartNode, neighbourPath);
                            simData.Queue.Enqueue(neighbourPath);
                            path.StartNode.OwnedPaths.Push(neighbourPath);
                        }
                    }
                    else if (neighbourPath.Distance == path.Distance + 1) // Another path with same length
                    {
                        neighbourPath.Parents.Add(path);
                    }
                }
            }



            // Iterate all dynamic blocks and calculate support ratio for each static
            foreach (var dyn in simData.DynamicBlocks)
            {
                dyn.PathCount = 1;

                if (dyn.Pos == new Vector3I(-6, 6, 0))
                {
                }
                // Uniform distribution
                //foreach (var s in dyn.Paths)
                //{
                //    s.Value.Ratio = 1.0f / dyn.Paths.Count;
                //}
                //continue;

                // Non-uniform distribution
                // Calculate angle between one vector and all other
                // Split weight support based on sum angle ratio
                float totalAngles = 0;
                if (dyn.Paths.Count > 1)
                {
                    foreach (var s in dyn.Paths)
                    {
                        Vector3 localVector1 = (dyn.Pos - s.Value.StartNode.Pos) * m_grid.GridSize;
                        Vector3 worldVector1 = Vector3.TransformNormal(localVector1, m_grid.WorldMatrix);

                        // float sumAngle = 0;
                        float sumAngleReduced = 0;
                        foreach (var s2 in dyn.Paths)
                        {
                            if (s.Key == s2.Key)
                            {
                                continue;
                            }

                            Vector3 localVector2 = (dyn.Pos - s2.Value.StartNode.Pos) * m_grid.GridSize;
                            Vector3 worldVector2 = Vector3.TransformNormal(localVector2, m_grid.WorldMatrix);
                            float   angle        = MyUtils.GetAngleBetweenVectorsAndNormalise(worldVector1, worldVector2);

                            float dot1 = Math.Abs(Vector3.Normalize(worldVector1).Dot(Vector3.Up));
                            float dot2 = Math.Abs(Vector3.Normalize(worldVector2).Dot(Vector3.Up));

                            float lowerBound = 0.1f;
                            dot1 = MathHelper.Lerp(lowerBound, 1, dot1);
                            dot2 = MathHelper.Lerp(lowerBound, 1, dot2);

                            float reducedAngle = angle;

                            if (!MyPetaInputComponent.OLD_SI)
                            {
                                //Reduce dependent on gravity
                                reducedAngle = angle * dot1 * s.Value.DirectionRatio;
                            }

                            //sumAngle += angle;
                            sumAngleReduced += reducedAngle;
                        }
                        s.Value.Ratio = sumAngleReduced;
                        totalAngles  += sumAngleReduced;
                    }

                    foreach (var s in dyn.Paths)
                    {
                        if (totalAngles > 0)
                        {
                            s.Value.Ratio /= totalAngles;
                            if (s.Value.Ratio < 0.000001f)
                            {
                                s.Value.Ratio = 0;
                            }
                        }
                        else
                        {
                            s.Value.Ratio = 1;
                        }
                    }
                }
                else
                {
                    foreach (var s in dyn.Paths)
                    {
                        s.Value.Ratio = 1.0f;
                    }
                }
            }

            // Iterate all static blocks and calculate support mass and mass transfer
            foreach (var staticBlock in simData.StaticBlocks)
            {
                // Initial mass and ratio
                foreach (var path in staticBlock.OwnedPaths)
                {
                    path.EndNode.TransferMass = 0;
                }

                // For each block in path (ordered by distance, furthest first)
                while (staticBlock.OwnedPaths.Count > 0)
                {
                    var pathInfo = staticBlock.OwnedPaths.Pop();
                    var node     = pathInfo.EndNode;

                    Debug.Assert(pathInfo.StartNode == staticBlock, "Wrong path");
                    Debug.Assert(!node.IsStatic, "Static node unexpected");

                    float outgoing = node.TransferMass + node.Mass * pathInfo.Ratio;
                    //float outgoindTotal = 0;
                    //foreach (var p in pathInfo.Parents)
                    //    outgoindTotal += p.DirectionRatio;

                    if (node.Pos == new Vector3I(-1, 1, 0))
                    {
                    }


                    float outgoingPerParent = outgoing / pathInfo.Parents.Count;

                    foreach (var parent in pathInfo.Parents)
                    {
                        var delta = parent.EndNode.Pos - node.Pos; // Node to parent
                        int index, parentIndex;
                        if (delta.X + delta.Y + delta.Z > 0)
                        {
                            index       = delta.Y + delta.Z * 2; // UnitX = 0, UnitY = 1, UnitZ = 2
                            parentIndex = index + 3;
                        }
                        else
                        {
                            index       = -delta.X * 3 - delta.Y * 4 - delta.Z * 5; // // -UnitX = 3, -UnitY = 4, -UnitZ = 5
                            parentIndex = index - 3;
                        }

                        //outgoingPerParent = outgoing * parent.DirectionRatio / outgoindTotal;

#if ENHANCED_DEBUG
                        node.OutgoingNodeswWithWeights[index].Add(new Tuple <Node, float>(parent.EndNode, outgoingPerParent));
#endif
                        if (index == 0 || index == 2 || index == 3 || index == 5)
                        {
                            node.SupportingWeights[index] -= node.PhysicalMaterial.HorisontalFragility * outgoingPerParent;
                        }
                        else
                        {
                            node.SupportingWeights[index] -= outgoingPerParent;
                        }

                        if (parentIndex == 0 || parentIndex == 2 || parentIndex == 3 || parentIndex == 5)
                        {
                            parent.EndNode.SupportingWeights[parentIndex] += parent.EndNode.PhysicalMaterial.HorisontalFragility * outgoingPerParent;
                        }
                        else
                        {
                            parent.EndNode.SupportingWeights[parentIndex] += outgoingPerParent;
                        }
#if ENHANCED_DEBUG
                        parent.EndNode.SupportingNodeswWithWeights[parentIndex].Add(new Tuple <Node, float>(node, outgoingPerParent));
#endif


                        parent.EndNode.TransferMass += outgoingPerParent;
                    }
                    node.TransferMass -= outgoing;
                }
            }


            using (Stats.Timing.Measure("SI - Sum", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag))
            {
                foreach (var node in simData.All)
                {
                    //node.Value.TotalSupportingWeight = 0;
                }

                foreach (var node in simData.All)
                {
                    if (node.Key == new Vector3I(-1, 1, 0))
                    {
                    }

                    float sum = 0;
                    for (int i = 0; i < 6; i++)
                    {
                        float sideWeight = node.Value.SupportingWeights[i];

                        sum += Math.Abs(sideWeight);
                        //sum = Math.Max(sum, Math.Abs(node.Value.SupportingWeights[i]));
                    }

                    if (!(sum == 0 && node.Value.PathCount == 0))
                    {
                        // sum = sum * 2 - 1;
                        node.Value.TotalSupportingWeight += node.Value.IsStatic ? 0 : (sum * 0.5f / node.Value.PathCount);
                    }
                }

                // Idea behind blur:
                // When block is supporting too much weight, it deforms still supports something, but allows neighbour block to support more weight, thus sharing support
                List <Node> supportingNeighbours = new List <Node>();
                foreach (var node in simData.All)
                {
                    supportingNeighbours.Clear();

                    float totalSharedSupport = node.Value.TotalSupportingWeight;
                    float totalMass          = node.Value.Mass;

                    foreach (var neighbour in node.Value.Neighbours)
                    {
                        bool isHorisontalNeighbour = neighbour.Pos.Y == node.Key.Y;
                        bool isVerticallySupported = neighbour.Paths.Any(x => (x.Key.Pos.X == node.Key.X && x.Key.Pos.Z == node.Key.Z));

                        if (isHorisontalNeighbour && isVerticallySupported)
                        {
                            totalSharedSupport += neighbour.TotalSupportingWeight;
                            totalMass          += neighbour.Mass;
                            supportingNeighbours.Add(neighbour);
                        }
                    }

                    if (supportingNeighbours.Count > 0)
                    {
                        float supportPerNode = totalSharedSupport / totalMass;
                        foreach (var neighbour in supportingNeighbours)
                        {
                            neighbour.TotalSupportingWeight = supportPerNode * neighbour.Mass;
                        }
                        node.Value.TotalSupportingWeight = supportPerNode * node.Value.Mass;
                    }
                }

                foreach (var node in simData.All)
                {
                    simData.TotalMax = Math.Max(simData.TotalMax, node.Value.TotalSupportingWeight);
                }

                // var timeMs = (Stopwatch.GetTimestamp() - ts) / (float)Stopwatch.Frequency * 1000.0f;
                //Console.WriteLine(String.Format("Generated structural integrity, time: {0}ms, object name: {1}", timeMs, m_grid.ToString()));
            }
        }
예제 #4
0
        private void LoadBlocks(GridSimulationData simData)
        {
            simData.BlockCount = m_grid.GetBlocks().Count;

            simData.All.Clear();
            simData.DynamicBlocks.Clear();
            simData.StaticBlocks.Clear();

            using (Stats.Timing.Measure("SI - Collect", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag))
            {
                // Store blocks
                foreach (var block in m_grid.GetBlocks())
                {
                    if (simData.All.ContainsKey(block.Position))
                    {
                        Debug.Fail("Same blocks in grid!");
                        continue;
                    }

                    bool isStatic = m_grid.Physics.Shape.BlocksConnectedToWorld.Contains(block.Position);

                    if (isStatic)
                    {
                        var n = new Node(block.Position, true);
                        n.PhysicalMaterial = block.BlockDefinition.PhysicalMaterial;
                        simData.StaticBlocks.Add(n);
                        simData.All.Add(block.Position, n);
                    }
                    else
                    {
                        float mass     = m_grid.Physics.Shape.GetBlockMass(block.Position);
                        var   cubeMass = MassToSI(mass);

                        var physicalMaterial = block.BlockDefinition.PhysicalMaterial;
                        if (block.FatBlock is MyCompoundCubeBlock)
                        {
                            var compBlock = block.FatBlock as MyCompoundCubeBlock;

                            physicalMaterial = compBlock.GetBlocks().First().BlockDefinition.PhysicalMaterial;

                            bool isGenerated = true;
                            foreach (var b in compBlock.GetBlocks())
                            {
                                if (!b.BlockDefinition.IsGeneratedBlock)
                                {
                                    isGenerated = false;
                                }
                                else
                                if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "Stone")
                                {
                                    isGenerated = false;
                                }
                            }

                            //we dont want to simulate these pieces..
                            if (isGenerated)
                            {
                                continue;
                            }
                        }



                        var node = new Node(block.Position, false);

                        node.Mass = cubeMass;

                        node.PhysicalMaterial = physicalMaterial;

                        simData.DynamicBlocks.Add(node);
                        simData.All.Add(block.Position, node);
                    }
                }

                foreach (var block in simData.DynamicWeights)
                {
                    if (simData.All.ContainsKey(block.Key))
                    {
                        simData.All[block.Key].Mass += block.Value;
                    }
                    else
                    {
                        var node = new Node(block.Key, false);
                        node.Mass            = simData.DynamicWeights[block.Key];
                        node.IsDynamicWeight = true;
                        simData.DynamicBlocks.Add(node);
                        simData.All.Add(block.Key, node);
                    }
                }
            }

            m_grid.Physics.ContactPointCallback -= Physics_ContactPointCallback;
            m_grid.Physics.ContactPointCallback += Physics_ContactPointCallback;

            AddNeighbours(simData);
        }
        private void FindAndCaculateFromAdvancedStatic(GridSimulationData simData)
        {
            // Instead of using uniform distribution of support between all fixed nodes, calculate non-uniform distribution based on vectors for few closest nodes
            // Use this distribution when setting support weight and transferring mass
            // SupportingWeights: x * support
            // ? TransferMass: x * numStaticBlocksForCurrentDynamicBlock * TransferMass

            int keepLookingDistance = (int)ClosestDistanceThreshold; // How far keep looking when closest static block is found
            simData.Queue.Clear();

            // Set initial distance to max for all dynamic
            foreach (var dyn in simData.DynamicBlocks)
            {
                dyn.Distance = int.MaxValue;
            }

            // Wide search from all static blocks
            foreach (var stat in simData.StaticBlocks)
            {
                stat.Distance = 0;
                var path = new PathInfo() { EndNode = stat, StartNode = stat, Distance = 0, DirectionRatio = 1 };
#if ENHANCED_DEBUG
                path.PathNodes.Add(stat);
#endif
                simData.Queue.Enqueue(path);
            }

            while (simData.Queue.Count > 0)
            {
                var path = simData.Queue.Dequeue();
                foreach (var neighbour in path.EndNode.Neighbours)
                {
                    if (neighbour.IsStatic)
                        continue;

                    PathInfo neighbourPath;
                    if (!neighbour.Paths.TryGetValue(path.StartNode, out neighbourPath))
                    {
                        if ((path.Distance - keepLookingDistance) <= neighbour.Distance)
                        {
                            neighbour.Distance = Math.Min(neighbour.Distance, path.Distance);

                            neighbourPath = new PathInfo();
                            neighbourPath.Distance = path.Distance + 1;
                            neighbourPath.StartNode = path.StartNode;
                            neighbourPath.EndNode = neighbour;
#if ENHANCED_DEBUG
                            neighbourPath.PathNodes = path.PathNodes.ToList();
                            neighbourPath.PathNodes.Add(neighbour);
#endif
                            neighbourPath.Parents.Add(path);
                            float t = neighbour.PhysicalMaterial.HorisontalTransmissionMultiplier * path.EndNode.PhysicalMaterial.HorisontalTransmissionMultiplier;

                            float massRatio = MathHelper.Clamp(path.EndNode.Mass / (neighbour.Mass + path.EndNode.Mass), 0, 1);

                            t *= neighbour.Mass * massRatio; //Horisontal transmission is very low on weak objects (floor, roof). Should be correctly get from mount point area
                            float[] horisontalTransmission = new float[] { t, 1, t };

                            int component = ((Vector3D)(neighbour.Pos - path.EndNode.Pos)).AbsMaxComponent();
                            neighbourPath.DirectionRatio = path.DirectionRatio * DirectionRatios[component] * horisontalTransmission[component];
                            neighbour.Paths.Add(path.StartNode, neighbourPath);
                            simData.Queue.Enqueue(neighbourPath);
                            path.StartNode.OwnedPaths.Push(neighbourPath);
                        }
                    }
                    else if (neighbourPath.Distance == path.Distance + 1) // Another path with same length
                    {
                        neighbourPath.Parents.Add(path);
                    }
                }
            }



            // Iterate all dynamic blocks and calculate support ratio for each static
            foreach (var dyn in simData.DynamicBlocks)
            {
                dyn.PathCount = 1;

                if (dyn.Pos == new Vector3I(-6, 6, 0))
                {
                }
                // Uniform distribution
                //foreach (var s in dyn.Paths)
                //{
                //    s.Value.Ratio = 1.0f / dyn.Paths.Count;
                //}
                //continue;

                // Non-uniform distribution
                // Calculate angle between one vector and all other
                // Split weight support based on sum angle ratio
                float totalAngles = 0;
                if (dyn.Paths.Count > 1)
                {
                    foreach (var s in dyn.Paths)
                    {
                        Vector3 localVector1 = (dyn.Pos - s.Value.StartNode.Pos) * m_grid.GridSize;
                        Vector3 worldVector1 = Vector3.TransformNormal(localVector1, m_grid.WorldMatrix);

                       // float sumAngle = 0;
                        float sumAngleReduced = 0;
                        foreach (var s2 in dyn.Paths)
                        {
                            if (s.Key == s2.Key)
                            {
                                continue;
                            }

                            Vector3 localVector2 = (dyn.Pos - s2.Value.StartNode.Pos) * m_grid.GridSize;
                            Vector3 worldVector2 = Vector3.TransformNormal(localVector2, m_grid.WorldMatrix);
                            float angle = MyUtils.GetAngleBetweenVectorsAndNormalise(worldVector1, worldVector2);

                            float dot1 = Math.Abs(Vector3.Normalize(worldVector1).Dot(Vector3.Up));
                            float dot2 = Math.Abs(Vector3.Normalize(worldVector2).Dot(Vector3.Up));

                            float lowerBound = 0.1f;
                            dot1 = MathHelper.Lerp(lowerBound, 1, dot1);
                            dot2 = MathHelper.Lerp(lowerBound, 1, dot2);

                            float reducedAngle = angle;

                            if (!MyPetaInputComponent.OLD_SI)
                            {
                                //Reduce dependent on gravity
                                reducedAngle = angle * dot1 * s.Value.DirectionRatio;
                            }

                            //sumAngle += angle;
                            sumAngleReduced += reducedAngle;
                        }
                        s.Value.Ratio = sumAngleReduced;
                        totalAngles += sumAngleReduced;
                    }

                    foreach (var s in dyn.Paths)
                    {
                        if (totalAngles > 0)
                        {
                            s.Value.Ratio /= totalAngles;
                            if (s.Value.Ratio < 0.000001f)
                                s.Value.Ratio = 0;
                        }
                        else
                            s.Value.Ratio = 1;
                    }
                }
                else
                {
                    foreach (var s in dyn.Paths)
                    {
                        s.Value.Ratio = 1.0f;
                    }
                }
            }

            // Iterate all static blocks and calculate support mass and mass transfer
            foreach (var staticBlock in simData.StaticBlocks)
            {
                // Initial mass and ratio
                foreach (var path in staticBlock.OwnedPaths)
                {
                    path.EndNode.TransferMass = 0;
                }

                // For each block in path (ordered by distance, furthest first)
                while (staticBlock.OwnedPaths.Count > 0)
                {
                    var pathInfo = staticBlock.OwnedPaths.Pop();
                    var node = pathInfo.EndNode;

                    Debug.Assert(pathInfo.StartNode == staticBlock, "Wrong path");
                    Debug.Assert(!node.IsStatic, "Static node unexpected");

                    float outgoing = node.TransferMass + node.Mass * pathInfo.Ratio;
                    //float outgoindTotal = 0;
                    //foreach (var p in pathInfo.Parents)
                    //    outgoindTotal += p.DirectionRatio;

                    if (node.Pos == new Vector3I(-1, 1, 0))
                    {
                    }


                    float outgoingPerParent = outgoing / pathInfo.Parents.Count;

                    foreach (var parent in pathInfo.Parents)
                    {
                        var delta = parent.EndNode.Pos - node.Pos; // Node to parent
                        int index, parentIndex;
                        if (delta.X + delta.Y + delta.Z > 0)
                        {
                            index = delta.Y + delta.Z * 2; // UnitX = 0, UnitY = 1, UnitZ = 2
                            parentIndex = index + 3;
                        }
                        else
                        {
                            index = -delta.X * 3 - delta.Y * 4 - delta.Z * 5; // // -UnitX = 3, -UnitY = 4, -UnitZ = 5
                            parentIndex = index - 3;
                        }

                        //outgoingPerParent = outgoing * parent.DirectionRatio / outgoindTotal;

#if ENHANCED_DEBUG
                        node.OutgoingNodeswWithWeights[index].Add(new Tuple<Node, float>(parent.EndNode, outgoingPerParent));
#endif
                        if (index == 0 || index == 2 || index == 3 || index == 5)
                        {
            
                            node.SupportingWeights[index] -= node.PhysicalMaterial.HorisontalFragility * outgoingPerParent;
                        }
                        else
                            node.SupportingWeights[index] -= outgoingPerParent;

                        if (parentIndex == 0 || parentIndex == 2 || parentIndex == 3 || parentIndex == 5)
                        {
                            parent.EndNode.SupportingWeights[parentIndex] += parent.EndNode.PhysicalMaterial.HorisontalFragility * outgoingPerParent;
                        }
                        else
                            parent.EndNode.SupportingWeights[parentIndex] +=  outgoingPerParent;
#if ENHANCED_DEBUG
                        parent.EndNode.SupportingNodeswWithWeights[parentIndex].Add(new Tuple<Node, float>(node, outgoingPerParent));
#endif


                        parent.EndNode.TransferMass += outgoingPerParent;
                    }
                    node.TransferMass -= outgoing;
                }
            }


            using (Stats.Timing.Measure("SI - Sum", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag))
            {
                foreach (var node in simData.All)
                {
                    //node.Value.TotalSupportingWeight = 0;
                }

                foreach (var node in simData.All)
                {
                    if (node.Key == new Vector3I(-1, 1, 0))
                    {
                    }

                    float sum = 0;
                    for (int i = 0; i < 6; i++)
                    {
                        float sideWeight = node.Value.SupportingWeights[i];

                        sum += Math.Abs(sideWeight);
                        //sum = Math.Max(sum, Math.Abs(node.Value.SupportingWeights[i]));
                    }

                    if (!(sum == 0 && node.Value.PathCount == 0))
                    {
                        // sum = sum * 2 - 1;
                        node.Value.TotalSupportingWeight += node.Value.IsStatic ? 0 : (sum * 0.5f / node.Value.PathCount);
                    }
                }

                // Idea behind blur:
                // When block is supporting too much weight, it deforms still supports something, but allows neighbour block to support more weight, thus sharing support
                List<Node> supportingNeighbours = new List<Node>();
                foreach (var node in simData.All)
                {
                    supportingNeighbours.Clear();

                    float totalSharedSupport = node.Value.TotalSupportingWeight;
                    float totalMass = node.Value.Mass;

                    foreach (var neighbour in node.Value.Neighbours)
                    {
                        bool isHorisontalNeighbour = neighbour.Pos.Y == node.Key.Y;
                        bool isVerticallySupported = neighbour.Paths.Any(x => (x.Key.Pos.X == node.Key.X && x.Key.Pos.Z == node.Key.Z));

                        if (isHorisontalNeighbour && isVerticallySupported)
                        {
                            totalSharedSupport += neighbour.TotalSupportingWeight;
                            totalMass += neighbour.Mass;
                            supportingNeighbours.Add(neighbour);
                        }
                    }

                    if (supportingNeighbours.Count > 0)
                    {
                        float supportPerNode = totalSharedSupport / totalMass;
                        foreach (var neighbour in supportingNeighbours)
                        {
                            neighbour.TotalSupportingWeight = supportPerNode * neighbour.Mass;
                        }
                        node.Value.TotalSupportingWeight = supportPerNode * node.Value.Mass;
                    }
                }

                foreach (var node in simData.All)
                {
                    simData.TotalMax = Math.Max(simData.TotalMax, node.Value.TotalSupportingWeight);
                }

                // var timeMs = (Stopwatch.GetTimestamp() - ts) / (float)Stopwatch.Frequency * 1000.0f;
                //Console.WriteLine(String.Format("Generated structural integrity, time: {0}ms, object name: {1}", timeMs, m_grid.ToString()));
            }
        }
 private void AddNeighbours(GridSimulationData simData)
 {
     using (Stats.Timing.Measure("SI - AddNeighbours", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag))
     {
         foreach (var node in simData.All)
         {
             foreach (var offset in Offsets)
             {
                 Node neighbour;
                 if (simData.All.TryGetValue(node.Value.Pos + offset, out neighbour))
                 {
                     node.Value.Neighbours.Add(neighbour);
                 }
             }
         }
     }
 }
        private void LoadBlocks(GridSimulationData simData)
        {
            simData.BlockCount = m_grid.GetBlocks().Count;

            simData.All.Clear();
            simData.DynamicBlocks.Clear();
            simData.StaticBlocks.Clear();

            using (Stats.Timing.Measure("SI - Collect", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag))
            {
                // Store blocks
                foreach (var block in m_grid.GetBlocks())
                {
                    if (simData.All.ContainsKey(block.Position))
                    {
                        Debug.Fail("Same blocks in grid!");
                        continue;
                    }

                    bool isStatic = m_grid.Physics.Shape.BlocksConnectedToWorld.Contains(block.Position);

                    if (isStatic)
                    {
                        var n = new Node(block.Position, true);
                        n.PhysicalMaterial = block.BlockDefinition.PhysicalMaterial;
                        simData.StaticBlocks.Add(n);
                        simData.All.Add(block.Position, n);
                    }
                    else 
                    {
                        

                        float mass = m_grid.Physics.Shape.GetBlockMass(block.Position);
                        var cubeMass = MassToSI(mass);

                        var physicalMaterial = block.BlockDefinition.PhysicalMaterial;
                        if (block.FatBlock is MyCompoundCubeBlock)
                        {
                            var compBlock = block.FatBlock as MyCompoundCubeBlock;

                            physicalMaterial = compBlock.GetBlocks().First().BlockDefinition.PhysicalMaterial;

                            bool isGenerated = true;
                            foreach (var b in compBlock.GetBlocks())
                            {
                                if (!b.BlockDefinition.IsGeneratedBlock)
                                    isGenerated = false;
                                else
                                    if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "Stone")
                                        isGenerated = false;
                                    else
                                        if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "RoofTile" && compBlock.GetBlocks().Count == 1)
                                        {
                                            isGenerated = false;
                                            cubeMass *= 6f;
                                        }
                            }

                            //we dont want to simulate these pieces..
                            if (isGenerated)
                                continue;
                        }



                        var node = new Node(block.Position, false);
                 
                        node.Mass = cubeMass;

                        node.PhysicalMaterial = physicalMaterial;

                        simData.DynamicBlocks.Add(node);
                        simData.All.Add(block.Position, node);
                    }
                }

                foreach (var block in simData.DynamicWeights)
                {
                    if (simData.All.ContainsKey(block.Key))
                    {
                        simData.All[block.Key].Mass += block.Value;
                    }
                    else
                    {
                        var node = new Node(block.Key, false);
                        node.Mass = simData.DynamicWeights[block.Key];
                        node.IsDynamicWeight = true;
                        simData.DynamicBlocks.Add(node);
                        simData.All.Add(block.Key, node);
                    }
                }
            }

            m_grid.Physics.ContactPointCallback -= Physics_ContactPointCallback;
            m_grid.Physics.ContactPointCallback += Physics_ContactPointCallback;

            AddNeighbours(simData);
        }
 void SwapSimulatedDatas()
 {
     var temp = m_finishedData;
     m_finishedData = m_simulatedData;
     m_simulatedData = temp;
 }
        private void LoadBlocks(GridSimulationData simData)
        {
            simData.BlockCount = m_grid.GetBlocks().Count;

            simData.All.Clear();
            simData.DynamicBlocks.Clear();
            simData.StaticBlocks.Clear();

            using (Stats.Timing.Measure("SI - Collect", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag))
            {
                // Store blocks
                foreach (var block in m_grid.GetBlocks())
                {
                    if (simData.All.ContainsKey(block.Position))
                    {
                        Debug.Fail("Same blocks in grid!");
                        continue;
                    }

                    bool isStatic = m_grid.Physics.Shape.BlocksConnectedToWorld.Contains(block.Position);

                    if (isStatic)
                    {
                        var n = new Node(block.Position, true);
                        n.PhysicalMaterial = block.BlockDefinition.PhysicalMaterial;
                        simData.StaticBlocks.Add(n);
                        simData.All.Add(block.Position, n);
                    }
                    else
                    {
                        float mass     = m_grid.Physics.Shape.GetBlockMass(block.Position);
                        var   cubeMass = MassToSI(mass);

                        var physicalMaterial = block.BlockDefinition.PhysicalMaterial;
                        if (block.FatBlock is MyCompoundCubeBlock)
                        {
                            var compBlock = block.FatBlock as MyCompoundCubeBlock;

                            physicalMaterial = compBlock.GetBlocks().First().BlockDefinition.PhysicalMaterial;

                            //Simulate blocks where or pieces are generated
                            bool allAreGenerated = true;
                            foreach (var b in compBlock.GetBlocks())
                            {
                                if (!b.BlockDefinition.IsGeneratedBlock)
                                {
                                    allAreGenerated = false;
                                    break;
                                }
                            }

                            bool isGenerated = true;
                            foreach (var b in compBlock.GetBlocks())
                            {
                                if (!b.BlockDefinition.IsGeneratedBlock)
                                {
                                    isGenerated = false;
                                    break;
                                }
                                else
                                if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "Stone")
                                {
                                    isGenerated = false;
                                    break;
                                }
                                else
                                if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "RoofTile" && allAreGenerated)
                                {
                                    isGenerated = false;
                                    cubeMass   *= 6f;
                                    break;
                                }
                                else
                                if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "RoofWood" && allAreGenerated)
                                {
                                    isGenerated = false;
                                    cubeMass   *= 3f;
                                    break;
                                }
                                else
                                if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "RoofHay" && allAreGenerated)
                                {
                                    isGenerated = false;
                                    cubeMass   *= 1.2f;
                                    break;
                                }
                                else
                                {
                                }
                            }

                            //we dont want to simulate these pieces..
                            if (isGenerated)
                            {
                                continue;
                            }
                        }

                        Vector3I pos         = block.Min;
                        float    volumeRecip = 1.0f / block.BlockDefinition.Size.Size;
                        for (var it = new Vector3I_RangeIterator(ref block.Min, ref block.Max); it.IsValid(); it.GetNext(out pos))
                        {
                            var node = new Node(pos, false);

                            node.Mass = cubeMass * volumeRecip;

                            node.PhysicalMaterial = physicalMaterial;

                            simData.DynamicBlocks.Add(node);
                            simData.All.Add(pos, node);
                        }
                    }
                }

                foreach (var block in simData.DynamicWeights)
                {
                    if (simData.All.ContainsKey(block.Key))
                    {
                        simData.All[block.Key].Mass += block.Value;
                    }
                    else
                    {
                        var node = new Node(block.Key, false);
                        node.Mass            = simData.DynamicWeights[block.Key];
                        node.IsDynamicWeight = true;
                        simData.DynamicBlocks.Add(node);
                        simData.All.Add(block.Key, node);
                    }
                }
            }

            m_grid.Physics.ContactPointCallback -= Physics_ContactPointCallback;
            m_grid.Physics.ContactPointCallback += Physics_ContactPointCallback;

            AddNeighbours(simData);
        }
        private void LoadBlocks(GridSimulationData simData)
        {
            simData.BlockCount = m_grid.GetBlocks().Count;

            simData.All.Clear();
            simData.DynamicBlocks.Clear();
            simData.StaticBlocks.Clear();

            using (Stats.Timing.Measure("SI - Collect", VRage.Stats.MyStatTypeEnum.Sum | VRage.Stats.MyStatTypeEnum.DontDisappearFlag))
            {
                // Store blocks
                foreach (var block in m_grid.GetBlocks())
                {
                    if (simData.All.ContainsKey(block.Position))
                    {
                        Debug.Fail("Same blocks in grid!");
                        continue;
                    }

                    bool isStatic = m_grid.Physics.Shape.BlocksConnectedToWorld.Contains(block.Position);

                    if (isStatic)
                    {
                        var n = new Node(block.Position, true);
                        n.PhysicalMaterial = block.BlockDefinition.PhysicalMaterial;
                        simData.StaticBlocks.Add(n);
                        simData.All.Add(block.Position, n);
                    }
                    else 
                    {
                        

                        float mass = m_grid.Physics.Shape.GetBlockMass(block.Position);
                        var cubeMass = MassToSI(mass);

                        var physicalMaterial = block.BlockDefinition.PhysicalMaterial;
                        if (block.FatBlock is MyCompoundCubeBlock)
                        {
                            var compBlock = block.FatBlock as MyCompoundCubeBlock;

                            physicalMaterial = compBlock.GetBlocks().First().BlockDefinition.PhysicalMaterial;

                            //Simulate blocks where or pieces are generated
                            bool allAreGenerated = true;
                            foreach (var b in compBlock.GetBlocks())
                            {
                                if (!b.BlockDefinition.IsGeneratedBlock)
                                {
                                    allAreGenerated = false;
                                    break;
                                }
                            }

                            bool isGenerated = true;
                            foreach (var b in compBlock.GetBlocks())
                            {
                                if (!b.BlockDefinition.IsGeneratedBlock)
                                {
                                    isGenerated = false;
                                    break;
                                }
                                else
                                    if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "Stone")
                                    {
                                        isGenerated = false;
                                        break;
                                    }
                                    else
                                        if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "RoofTile" && allAreGenerated)
                                        {
                                            isGenerated = false;
                                            cubeMass *= 6f;
                                            break;
                                        }
                                        else
                                            if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "RoofWood" && allAreGenerated)
                                            {
                                                isGenerated = false;
                                                cubeMass *= 3f;
                                                break;
                                            }
                                            else
                                                if (b.BlockDefinition.IsGeneratedBlock && b.BlockDefinition.PhysicalMaterial.Id.SubtypeName == "RoofHay" && allAreGenerated)
                                                {
                                                    isGenerated = false;
                                                    cubeMass *= 1.2f;
                                                    break;
                                                }
                                                else
                                                {
                                                }
                            }

                            //we dont want to simulate these pieces..
                            if (isGenerated)
                                continue;
                        }

                        Vector3I pos = block.Min;
                        float volumeRecip = 1.0f / block.BlockDefinition.Size.Size;
                        for (var it = new Vector3I_RangeIterator(ref block.Min, ref block.Max); it.IsValid(); it.GetNext(out pos))
                        {
                            var node = new Node(pos, false);

                            node.Mass = cubeMass * volumeRecip;

                            node.PhysicalMaterial = physicalMaterial;

                            simData.DynamicBlocks.Add(node);
                            simData.All.Add(pos, node);
                        }
                    }
                }

                foreach (var block in simData.DynamicWeights)
                {
                    if (simData.All.ContainsKey(block.Key))
                    {
                        simData.All[block.Key].Mass += block.Value;
                    }
                    else
                    {
                        var node = new Node(block.Key, false);
                        node.Mass = simData.DynamicWeights[block.Key];
                        node.IsDynamicWeight = true;
                        simData.DynamicBlocks.Add(node);
                        simData.All.Add(block.Key, node);
                    }
                }
            }

            m_grid.Physics.ContactPointCallback -= Physics_ContactPointCallback;
            m_grid.Physics.ContactPointCallback += Physics_ContactPointCallback;

            AddNeighbours(simData);
        }