Beispiel #1
0
        public Cargo_ShipPart(ShipPartDNA dna, ItemOptions options, EditorOptions editorOptions)
            : base(CargoType.ShipPart)
        {
            PartDesignBase part = BotConstructor.GetPartDesign(dna, editorOptions, true);

            //TODO: This is really ineficient, let design calculate it for real
            //TODO: Volume and Mass should be calculated by the design class (add to PartBase interface)
            var aabb = Math3D.GetAABB(UtilityWPF.GetPointsFromMesh(part.Model));

            this.Volume = (aabb.Item2.X - aabb.Item1.X) * (aabb.Item2.Y - aabb.Item1.Y) * (aabb.Item2.Y - aabb.Item1.Y);

            //TODO: Let the design class return this (expose a property called DryDensity)
            this.Density = Math1D.Avg(options.Thruster_Density, options.Sensor_Density);

            this.PartDNA = dna;
        }
Beispiel #2
0
        public static HullVoronoiExploder_Response ShootHull(ITriangleIndexed[] convexHull, Tuple <Point3D, Vector3D, double>[] shots, HullVoronoiExploder_Options options = null)
        {
            options = options ?? new HullVoronoiExploder_Options();

            var    aabb    = Math3D.GetAABB(convexHull);
            double aabbLen = (aabb.Item2 - aabb.Item1).Length;

            // Create a voronoi, and intersect with the hull
            Tuple <HullVoronoiExploder_Response, bool> retVal = null;

            for (int cntr = 0; cntr < 15; cntr++)
            {
                try
                {
                    retVal = SplitHull(convexHull, shots, options, aabbLen);
                    break;
                }
                catch (Exception)
                {
                    // Every once in a while, there is an error with the voronoi, or voronoi intersecting the hull, etc.  Just try
                    // again with new random points
                }
            }

            if (retVal == null)
            {
                return(null);
            }
            else if (!retVal.Item2)
            {
                return(retVal.Item1);
            }

            // Figure out velocities
            retVal.Item1.Velocities = GetVelocities(retVal.Item1.Shards, retVal.Item1.Hits, Math.Sqrt(aabbLen / 2), options);

            return(retVal.Item1);
        }
Beispiel #3
0
        private static Tuple <HullVoronoiExploder_Response, bool> SplitHull(ITriangleIndexed[] convexHull, Tuple <Point3D, Vector3D, double>[] shots, HullVoronoiExploder_Options options, double aabbLen)
        {
            #region intersect with the hull

            var hits = shots.
                       Select(o => new HullVoronoiExploder_ShotHit()
            {
                Shot = o,
                Hit  = GetHit(convexHull, o.Item1, o.Item2, o.Item3),
            }).
                       Where(o => o.Hit != null).
                       ToArray();

            if (hits.Length == 0)
            {
                return(null);
            }

            #endregion

            #region voronoi

            Point3D[] controlPoints = GetVoronoiCtrlPoints(hits, convexHull, options.MinCount, options.MaxCount, aabbLen);

            VoronoiResult3D voronoi = Math3D.GetVoronoi(controlPoints, true);
            if (voronoi == null)
            {
                return(null);
            }

            #endregion

            // There is enough to start populating the response
            HullVoronoiExploder_Response retVal = new HullVoronoiExploder_Response()
            {
                Hits          = hits,
                ControlPoints = controlPoints,
                Voronoi       = voronoi,
            };

            #region intersect voronoi and hull

            // Intersect
            Tuple <int, ITriangleIndexed[]>[] shards = null;
            try
            {
                shards = Math3D.GetIntersection_Hull_Voronoi_full(convexHull, voronoi);
            }
            catch (Exception)
            {
                return(Tuple.Create(retVal, false));
            }

            if (shards == null)
            {
                return(Tuple.Create(retVal, false));
            }

            // Smooth
            if (options.ShouldSmoothShards)
            {
                shards = shards.
                         Select(o => Tuple.Create(o.Item1, Asteroid.SmoothTriangles(o.Item2))).
                         ToArray();
            }

            // Validate
            shards = shards.
                     Where(o => o.Item2 != null && o.Item2.Length >= 3).
                     Where(o =>
            {
                Vector3D firstNormal = o.Item2[0].NormalUnit;
                return(o.Item2.Skip(1).Any(p => !Math.Abs(Vector3D.DotProduct(firstNormal, p.NormalUnit)).IsNearValue(1)));
            }).
                     ToArray();

            if (shards.Length == 0)
            {
                return(Tuple.Create(retVal, false));
            }

            #endregion

            #region populate shards

            retVal.Shards = shards.
                            Select(o =>
            {
                var aabb = Math3D.GetAABB(o.Item2);

                double radius = Math.Sqrt((aabb.Item2 - aabb.Item1).Length / 2);

                Point3D center      = Math3D.GetCenter(TriangleIndexed.GetUsedPoints(o.Item2));
                Vector3D centerVect = center.ToVector();

                Point3D[] allPoints = o.Item2[0].AllPoints.
                                      Select(p => p - centerVect).
                                      ToArray();

                TriangleIndexed[] shiftedTriangles = o.Item2.
                                                     Select(p => new TriangleIndexed(p.Index0, p.Index1, p.Index2, allPoints)).
                                                     ToArray();

                return(new HullVoronoiExploder_Shard()
                {
                    VoronoiControlPointIndex = o.Item1,
                    Hull_ParentCoords = o.Item2,
                    Hull_Centered = shiftedTriangles,
                    Radius = radius,
                    Center_ParentCoords = center,
                });
            }).
                            Where(o => o != null).
                            ToArray();

            #endregion

            return(Tuple.Create(retVal, true));
        }
Beispiel #4
0
        private static NeuronMapping[] MapNeurons(Point3D[] externalPoints, Point3D[] internalPoints)
        {
            // FuzzyLink wasn't designed for from and to points to be sitting on top of each other, so need to pull them apart
            //
            // external is pulled to -Z, internal is +Z.  These offset coordinates don't have any meaning outside this function, they are just
            // a hack to allow FuzzyLink to work properly

            // Figure out how far to separate them to ensure they are fully separated
            var    aabb       = Math3D.GetAABB(externalPoints.Concat(internalPoints));
            double offsetDist = Math1D.Max(aabb.Item2.X - aabb.Item1.X, aabb.Item2.Y - aabb.Item1.Y, aabb.Item2.Z - aabb.Item1.Z);

            offsetDist *= 3;
            Vector3D offset = new Vector3D(0, 0, offsetDist);

            // Create seed links.  The easiest approach is just to create one per internal point and then let the fuzzy linker find the best
            // external point
            //
            // I could see the argument for remembering the links across generations so that if the external points drift around too much,
            // the original linking will better persist.  But if the bot is mutating that much over generations, the neat NN should be retrained
            // from time to time.  Also, if a mismapping causes the bot to perform bad, then it won't be making children (and a mismapping
            // might end up causing better performance)
            Tuple <Point3D, Point3D, double>[] initialLinks = internalPoints.
                                                              Select(o => Tuple.Create(o - offset, o + offset, 1d)).
                                                              ToArray();

            Point3D[] pointsForFuzzy = externalPoints.Select(o => o - offset).
                                       Concat(internalPoints.Select(o => o + offset)).
                                       ToArray();

            // Allow a few more links than points.  If the external and internal points are aligned well, then the extra link allowance won't
            // be used
            int numLinks = (internalPoints.Length * 1.1).ToInt_Ceiling();

            var finalLinks = ItemLinker.FuzzyLink(initialLinks, pointsForFuzzy, numLinks, 6);


            const double THICKNESS = .005;
            const double DOT       = THICKNESS * 3;

            Debug3DWindow window = new Debug3DWindow();

            window.AddDots(externalPoints, DOT, Colors.IndianRed);
            window.AddDots(internalPoints, DOT, Colors.DodgerBlue);

            window.AddDots(pointsForFuzzy, DOT, Colors.Silver);
            window.AddLines(initialLinks.Select(o => (o.Item1, o.Item2)), THICKNESS, Colors.Orchid);


            List <NeuronMapping> retVal = new List <NeuronMapping>();

            foreach (var link in finalLinks)
            {
                int?externalIndex = null;
                int?internalIndex = null;

                foreach (int index in new[] { link.Item1, link.Item2 })
                {
                    if (index < externalPoints.Length)
                    {
                        externalIndex = index;
                    }
                    else
                    {
                        internalIndex = index - externalPoints.Length;
                    }
                }

                if (externalIndex == null || internalIndex == null)
                {
                    // This should never happen in practice, the internal and external sets are pulled too far apart to accidentally be linked together.
                    // Just ignore this link
                    continue;
                }

                retVal.Add(new NeuronMapping()
                {
                    Index_External = externalIndex.Value,
                    Index_NEAT     = internalIndex.Value,
                    Weight         = link.Item3,
                });
            }


            foreach (var link in finalLinks)
            {
                window.AddLine(pointsForFuzzy[link.Item1], pointsForFuzzy[link.Item2], THICKNESS * link.Item3, Colors.GhostWhite);
            }
            foreach (var link in retVal)
            {
                window.AddLine(externalPoints[link.Index_External], internalPoints[link.Index_NEAT], THICKNESS * link.Weight, Colors.Coral);
            }

            window.Show();

            return(retVal.ToArray());
        }
Beispiel #5
0
        private void ChooseForcePoints()
        {
            SortedList <int, List <Point3D>[]> pointSets = new SortedList <int, List <Point3D>[]>();

            for (int cntr = 0; cntr < _numSets; cntr++)
            {
                //TODO:  This method should return barycentric coords directly
                // Create random points across the triangles
                SortedList <int, List <Point3D> > points = Math3D.GetRandomPoints_OnHull_Structured(_triangles, _numPointsPerSet);

                // Add these to the sets
                foreach (int triangleIndex in points.Keys)
                {
                    if (!pointSets.ContainsKey(triangleIndex))
                    {
                        pointSets.Add(triangleIndex, new List <Point3D> [_numSets]);
                    }

                    pointSets[triangleIndex][cntr] = points[triangleIndex];
                }
            }

            foreach (int triangleIndex in pointSets.Keys)
            {
                List <Vector[]> localSets = new List <Vector[]>();

                for (int setCntr = 0; setCntr < _numSets; setCntr++)
                {
                    List <Point3D> points = pointSets[triangleIndex][setCntr];

                    if (points == null || points.Count == 0)
                    {
                        localSets.Add(null);
                        continue;
                    }

                    Vector[] set = new Vector[points.Count];
                    localSets.Add(set);

                    for (int cntr = 0; cntr < points.Count; cntr++)
                    {
                        set[cntr] = Math3D.ToBarycentric(this.Triangles[triangleIndex], points[cntr]);
                    }
                }

                // Store these sets in this triangle
                this.Triangles[triangleIndex].StoreForcePointSets(localSets);
            }

            // Calculate the sample radius
            if (_triangles.Length > 0)
            {
                // The sum of the volumes of point samples needs to equal the volume of the hull:
                // N(4/3 pi r^3)=Vol
                // r=cube root((Vol/N)/(4/3 pi))

                var aabb = Math3D.GetAABB(_triangles[0].AllPoints);     // using AABB as a safe way to get the volume of the hull

                double volume = Math.Abs(aabb.Item2.X - aabb.Item1.X) * Math.Abs(aabb.Item2.Y - aabb.Item1.Y) * Math.Abs(aabb.Item2.Z - aabb.Item1.Z);

                double intermediate = (volume / _numPointsPerSet) / ((4d / 3d) * Math.PI);

                _sampleRadius = Math.Abs(Math.Pow(intermediate, 1d / 3d));
            }
            else
            {
                _sampleRadius = 0d;
            }
        }