private static GeometryModel3D GetModel_WoodIron_Ring_Band(double ballRadius, double z, System.Windows.Media.Media3D.Material material, TriangleIndexed[] ball, SortedList <string, double> from, SortedList <string, double> to, string prefix) { const double ENLARGE = 1.04d; GeometryModel3D retVal = new GeometryModel3D(); retVal.Material = material; retVal.BackMaterial = material; double bandHeight = WeaponDNA.GetKeyValue(prefix + "Height", from, to, StaticRandom.NextPercent(ballRadius * .15, .5)); double bandHeightHalf = bandHeight / 2d; // Slice the hull at the top and bottom band z's Point3D[] slice1 = Math3D.GetIntersection_Hull_Plane(ball, new Triangle(new Point3D(0, 0, z - bandHeightHalf), new Point3D(1, 0, z - bandHeightHalf), new Point3D(0, 1, z - bandHeightHalf))); Point3D[] slice2 = Math3D.GetIntersection_Hull_Plane(ball, new Triangle(new Point3D(0, 0, z + bandHeightHalf), new Point3D(1, 0, z + bandHeightHalf), new Point3D(0, 1, z + bandHeightHalf))); // Enlarge those polygons xy, leave z alone slice1 = slice1.Select(o => new Point3D(o.X * ENLARGE, o.Y * ENLARGE, o.Z)).ToArray(); slice2 = slice2.Select(o => new Point3D(o.X * ENLARGE, o.Y * ENLARGE, o.Z)).ToArray(); // Now turn those two polygons into a 3d hull TriangleIndexed[] band = Math3D.GetConvexHull(UtilityCore.Iterate(slice1, slice2).ToArray()); retVal.Geometry = UtilityWPF.GetMeshFromTriangles(band); return(retVal); }
private void Window_Loaded(object sender, RoutedEventArgs e) { try { #region Trackball // Camera Trackball _trackball = new TrackBallRoam(_camera); //_trackball.ShouldHitTestOnOrbit = true; _trackball.EventSource = grdViewPort; //NOTE: If this control doesn't have a background color set, the trackball won't see events (I think transparent is ok, just not null) _trackball.AllowZoomOnMouseWheel = true; _trackball.Mappings.AddRange(TrackBallMapping.GetPrebuilt(TrackBallMapping.PrebuiltMapping.MouseComplete)); //_trackball.GetOrbitRadius += new GetOrbitRadiusHandler(Trackball_GetOrbitRadius); #endregion //Material _material = new MaterialGroup(); RefreshColors(); // Visuals AddVisual(UtilityWPF.GetCylinder_AlongX(60, 1, 2), new Point3D(-2.5, 2.5, 0)); AddVisual(UtilityWPF.GetCube_IndependentFaces(new Point3D(-1, -1, -1), new Point3D(1, 1, 1)), new Point3D(2.5, 2.5, 0)); AddVisual(UtilityWPF.GetSphere_LatLon(20, 1), new Point3D(-2.5, -2.5, 0)); var hull = Math3D.GetConvexHull(Enumerable.Range(0, 40).Select(o => Math3D.GetRandomVector_Spherical(1.1, 1.3).ToPoint()).ToArray()); AddVisual(UtilityWPF.GetMeshFromTriangles(hull), new Point3D(2.5, -2.5, 0)); AddVisual(UtilityWPF.GetMeshFromTriangles_IndependentFaces(hull), new Point3D(2.5, -6, 0)); // Timer _timer = new DispatcherTimer(); _timer.Interval = TimeSpan.FromMilliseconds(20); _timer.Tick += Timer_Tick; _timer.Start(); _isInitialized = true; RefreshColors(); } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
/// <summary> /// This is exposed so it can be called externally on a separate thread, then call this asteroid's constructor /// in the main thread once this returns /// </summary> public static ITriangleIndexed[] GetHullTriangles(double radius) { const int NUMPOINTS = 60; // too many, and it looks too perfect Exception lastException = null; Random rand = StaticRandom.GetRandomForThread(); for (int infiniteLoopCntr = 0; infiniteLoopCntr < 50; infiniteLoopCntr++) // there is a slight chance that the convex hull generator will choke on the inputs. If so just retry { try { double minRadius = radius * .9d; Point3D[] points = new Point3D[NUMPOINTS]; // Make a point cloud for (int cntr = 0; cntr < NUMPOINTS; cntr++) { points[cntr] = Math3D.GetRandomVector_Spherical(minRadius, radius).ToPoint(); } // Squash it Transform3DGroup transform = new Transform3DGroup(); transform.Children.Add(new ScaleTransform3D(.33d + (rand.NextDouble() * .66d), .33d + (rand.NextDouble() * .66d), 1d)); // squash it transform.Children.Add(new RotateTransform3D(new QuaternionRotation3D(Math3D.GetRandomRotation()))); // giving it a random rotation, since it's always squashed along the same axiis transform.Transform(points); // Get a hull that wraps those points ITriangleIndexed[] retVal = Math3D.GetConvexHull(points.ToArray()); // Get rid of unused points retVal = TriangleIndexed.Clone_CondensePoints(retVal); // Exit Function return(retVal); } catch (Exception ex) { lastException = ex; } } throw new ApplicationException(lastException.ToString()); }
private static Model3DGroup GetModel_WoodIron(WeaponSpikeBallDNA dna, WeaponSpikeBallDNA finalDNA, WeaponMaterialCache materials) { Model3DGroup retVal = new Model3DGroup(); Random rand = StaticRandom.GetRandomForThread(); var from = dna.KeyValues; var to = finalDNA.KeyValues; double spikeLength = dna.Radius * 1.4d; double ballRadius = dna.Radius * 1d; double spikeRadius = dna.Radius * .2; #region Ball System.Windows.Media.Media3D.Material material = materials.Ball_Wood; // the property get returns a slightly random color GeometryModel3D geometry = new GeometryModel3D(); geometry.Material = material; geometry.BackMaterial = material; // Create a convex hull out of semi evenly distibuted points int numHullPoints = Convert.ToInt32(WeaponDNA.GetKeyValue("numHullPoints", from, to, rand.Next(20, 50))); TriangleIndexed[] ball = Math3D.GetConvexHull(Math3D.GetRandomVectors_SphericalShell_EvenDist(numHullPoints, ballRadius, .03, 10).Select(o => o.ToPoint()).ToArray()); geometry.Geometry = UtilityWPF.GetMeshFromTriangles(ball); retVal.Children.Add(geometry); #endregion // These are placed where the rings are, to push spikes away (so that spikes don't poke through the rings) List <Vector3D> staticPoints = new List <Vector3D>(); #region Rings material = materials.Spike_Iron; // the property get returns a slightly random color // 0, 1 or 2 rings. Higher chance of 0 than 2 int numRings = Convert.ToInt32(WeaponDNA.GetKeyValue("numRings", from, to, Math.Floor(rand.NextPow(2, 2.3)))); double[] zs = new double[0]; switch (numRings) { case 0: break; case 1: zs = new double[] { WeaponDNA.GetKeyValue("ringZ1", from, to, Math1D.GetNearZeroValue(ballRadius * .75)) }; break; case 2: double z1 = WeaponDNA.GetKeyValue("ringZ1", from, to, Math1D.GetNearZeroValue(ballRadius * .75)); double z2 = 0; if (from == null || !from.TryGetValue("ringZ2", out z2)) { do { z2 = Math1D.GetNearZeroValue(ballRadius * .75); } while (Math.Abs(z1 - z2) < ballRadius * .4); to.Add("ringZ2", z2); } zs = new double[] { z1, z2 }; break; default: throw new ApplicationException("Unexpected number of rings: " + numRings.ToString()); } // Build the rings at the z offsets that were calculated above for (int cntr = 0; cntr < zs.Length; cntr++) { retVal.Children.Add(GetModel_WoodIron_Ring_Band(ballRadius, zs[cntr], material, ball, from, to, "ringZ" + cntr.ToString())); // Store points at the rings double ringRadiusAvg = Math.Sqrt((ballRadius * ballRadius) - (zs[cntr] * zs[cntr])); staticPoints.AddRange(Math2D.GetCircle_Cached(7).Select(o => (o.ToVector() * ringRadiusAvg).ToVector3D(zs[cntr]))); } #endregion #region Spikes Vector3D[] staticPointsArr = staticPoints.Count == 0 ? null : staticPoints.ToArray(); double[] staticRepulse = staticPoints.Count == 0 ? null : Enumerable.Range(0, staticPoints.Count).Select(o => .005d).ToArray(); int numSpikes = Convert.ToInt32(WeaponDNA.GetKeyValue("numSpikes", from, to, rand.Next(8, 14))); Vector3D[] spikeLocations; if (from != null && from.ContainsKey("spikeLoc0X")) { spikeLocations = new Vector3D[numSpikes]; for (int cntr = 0; cntr < numSpikes; cntr++) { string prefix = "spikeLoc" + cntr.ToString(); spikeLocations[cntr] = new Vector3D(to[prefix + "X"], to[prefix + "Y"], to[prefix + "Z"]); } } else { spikeLocations = Math3D.GetRandomVectors_SphericalShell_EvenDist(numSpikes, ballRadius, .03, 10, null, staticPointsArr, staticRepulse); for (int cntr = 0; cntr < numSpikes; cntr++) { string prefix = "spikeLoc" + cntr.ToString(); to.Add(prefix + "X", spikeLocations[cntr].X); to.Add(prefix + "Y", spikeLocations[cntr].Y); to.Add(prefix + "Z", spikeLocations[cntr].Z); } } for (int cntr = 0; cntr < spikeLocations.Length; cntr++) { material = materials.Spike_Iron; // the property get returns a slightly random color geometry = new GeometryModel3D(); geometry.Material = material; geometry.BackMaterial = material; RotateTransform3D transform = new RotateTransform3D(new QuaternionRotation3D(Math3D.GetRotation(new Vector3D(0, 0, 1), spikeLocations[cntr]))); // the tube builds along z List <TubeRingBase> rings = new List <TubeRingBase>(); double spikeRadiusA = WeaponDNA.GetKeyValue("spikeRad" + cntr.ToString(), from, to, rand.NextPercent(spikeRadius, .33)); rings.Add(new TubeRingRegularPolygon(0, false, spikeRadiusA, spikeRadiusA, false)); rings.Add(new TubeRingPoint(WeaponDNA.GetKeyValue("spikeLen" + cntr.ToString(), from, to, rand.NextDouble(spikeLength * .9, spikeLength * 1.1)), false)); int numSegments = Convert.ToInt32(WeaponDNA.GetKeyValue("spikeSegs" + cntr.ToString(), from, to, rand.Next(3, 6))); bool isSoft = Math1D.IsNearZero(WeaponDNA.GetKeyValue("spikeSoft" + cntr.ToString(), from, to, rand.Next(2))); geometry.Geometry = UtilityWPF.GetMultiRingedTube(numSegments, rings, isSoft, false, transform); retVal.Children.Add(geometry); } #endregion return(retVal); }