private void ShootTwoShots_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (_asteroid == null)
                {
                    MessageBox.Show("Need to make an asteroid first", this.Title, MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }

                ClearShots();

                // Work backward to make sure the shots don't miss
                Point3D pointInside1 = Math3D.GetRandomVector_Spherical(MAXRADIUS / 3).ToPoint();
                Point3D pointInside2 = Math3D.GetRandomVector_Spherical(MAXRADIUS / 3).ToPoint();

                Vector3D directionOut1 = Math3D.GetRandomVector_Spherical_Shell(MAXRADIUS * 3);
                Vector3D directionOut2 = Math3D.RotateAroundAxis(directionOut1, Math3D.GetRandomVector_Spherical_Shell(1), Math1D.DegreesToRadians(Math1D.GetNearZeroValue(30)));

                _shots = new[]
                {
                    Tuple.Create(pointInside1 + directionOut1, -directionOut1, 1d),
                    Tuple.Create(pointInside2 + directionOut2, -directionOut2, 1d),
                };

                // Find the deepest point of intersection
                var hits = _shots.
                    Select(o => Math3D.GetIntersection_Hull_Ray(_asteroid, o.Item1, o.Item2)).
                    ToArray();

                if (hits.Length != 2 || hits.Any(o => o.Length != 2))
                {
                    MessageBox.Show("Expected two hits: " + hits.Length.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                // Voronoi
                Point3D[] controlPoints = GetVoronoiCtrlPoints_TwoLines(hits, _asteroid);

                _voronoi = Math3D.GetVoronoi(controlPoints, true);

                DrawShatteredAsteroid_ORIG();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
示例#2
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));
        }
        private void ShootOneShot_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                if (_asteroid == null)
                {
                    MessageBox.Show("Need to make an asteroid first", this.Title, MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }

                ClearShots();

                // Work backward to make sure the shot doesn't miss
                Point3D pointInside = Math3D.GetRandomVector_Spherical(MAXRADIUS / 3).ToPoint();
                Vector3D directionOut = Math3D.GetRandomVector_Spherical_Shell(MAXRADIUS * 3);

                _shots = new[]
                {
                    Tuple.Create(pointInside + directionOut, -directionOut, 1d),
                };

                // Find the deepest point of intersection
                var hits = Math3D.GetIntersection_Hull_Ray(_asteroid, _shots[0].Item1, _shots[0].Item2);
                if (hits.Length != 2)
                {
                    MessageBox.Show("Expected two hits: " + hits.Length.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
                    return;
                }

                //TODO: Put a point in front, then remove that subhull.  This will look like exploded material
                //or, put it on the same plane, and a cylinder will get cored out
                //Point3D[] controlPoints = GetVoronoiCtrlPoints_AroundLine_Simple(hits[0].Item1, hits[1].Item1, StaticRandom.Next(2, 7));
                Point3D[] controlPoints = GetVoronoiCtrlPoints_AroundLine(hits[0].Item1, hits[1].Item1);

                _voronoi = Math3D.GetVoronoi(controlPoints, true);

                DrawShatteredAsteroid_ORIG();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }
        private void ProcessShots_ORIG()
        {
            // Intersect with the asteroid
            #region ORIG
            //var hits = _shots.
            //    Select(o =>
            //    {
            //        var intersections = Math3D.GetIntersection_Hull_Ray(_asteroid, o.Item1, o.Item2);

            //        if (intersections.Length != 2)
            //        {
            //            return (Tuple<Point3D, Point3D>)null;
            //        }

            //        Vector3D penetrate = (intersections[1].Item1 - intersections[0].Item1) * o.Item3;

            //        return Tuple.Create(intersections[0].Item1, intersections[0].Item1 + penetrate);
            //    }).
            //    Where(o => o != null).
            //    ToArray();
            #endregion
            var hits = _shots.
                Select(o => new ShotHit()
                {
                    Shot = o,
                    Hit = ExplosionForceWorker.GetHit(_asteroid, o.Item1, o.Item2, o.Item3),
                }).
                Where(o => o != null).
                ToArray();

            if (hits.Length == 0)
            {
                if (_shots != null)
                {
                    foreach (var shot in _shots)
                    {
                        DrawShot(shot.Item1, shot.Item2 * 2);
                    }
                }

                _voronoi = null;
                DrawAsteroid(_asteroid);
                return;
            }

            // Voronoi
            Point3D[] controlPoints = ExplosionForceWorker.GetVoronoiCtrlPoints(hits, _asteroid);

            _voronoi = Math3D.GetVoronoi(controlPoints, true);

            DrawShatteredAsteroid_ORIG();
        }
        private void ClearShots()
        {
            _shots = null;
            _voronoi = null;
            _explosion = null;

            ClearVisuals();
        }
        private void ClearClickRayData()
        {
            _voronoi2NeighborRayStarts.Clear();
            _voronoiResult = null;

            _viewportFull.Children.RemoveAll(_clickRays3D.Select(o => o.Visual));
            _clickRays3D.Clear();
        }
        private void btn3DVoronoiDelaunay_Click(object sender, RoutedEventArgs e)
        {
            const double DELAUNAYRADIUS = .008;
            const double VORONOIRADIUS = .015;

            try
            {
                PrepFor3D();
                ClearTempVisuals();

                _voronoiResult = Math3D.GetVoronoi(_dots3D.SelectMany(o => o.Positions).ToArray(), true);

                // Delaunay
                _misc3D.Add(new Item3D(AddLines(_viewportFull, Tetrahedron.GetUniqueLines(_voronoiResult.Delaunay), _voronoiResult.ControlPoints, UtilityWPF.ColorFromHex("40000000"), DELAUNAYRADIUS)));

                // Voronoi Interior Edges
                var interiorEdges = _voronoiResult.Edges.
                    Where(o => o.EdgeType == EdgeType.Segment).
                    Select(o => Tuple.Create(o.Index0, o.Index1.Value));

                _misc3D.Add(new Item3D(AddLines(_viewportFull, interiorEdges, _voronoiResult.EdgePoints, Colors.White, VORONOIRADIUS)));

                // Voronoi Rays
                #region all same color

                //var rays = _voronoiResult.Edges.
                //    Where(o => o.EdgeType == EdgeType.Ray).
                //    Select(o => Tuple.Create(o.Point0, o.Point0 + (o.Direction.Value * RAYLENGTH)));

                //_misc3D.Add(new Item3D(AddLines(_viewportFull, rays, Colors.Cornsilk, VORONOIRADIUS)));

                #endregion
                #region color by count

                var raysByIndex = _voronoiResult.Edges.
                    Where(o => o.EdgeType == EdgeType.Ray).
                    ToLookup(o => o.Index0);

                var raysByCount = raysByIndex.
                    Select(o => new { Count = o.Count(), Rays = o }).
                    ToLookup(o => o.Count);

                foreach (var raySet in raysByCount)
                {
                    var rayTuples = raySet.
                        SelectMany(o => o.Rays).
                        Select(o => Tuple.Create(o.Point0, o.Point0 + (o.Direction.Value * RAYLENGTH)));

                    Color color;
                    switch (raySet.Key)
                    {
                        case 1:
                            color = Colors.Cornsilk;
                            break;
                        case 2:
                            color = Colors.Honeydew;
                            break;
                        default:
                            color = Colors.Violet;
                            break;
                    }

                    _misc3D.Add(new Item3D(AddLines(_viewportFull, rayTuples, color, VORONOIRADIUS)));
                }

                #endregion
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error);
            }
        }