private static Model3D[] CreateIcons_Rotate(double arcRadius, double arcThickness, double arrowThickness, double sphereRadius) { const int NUMSIDES_TOTAL = 13; const int NUMSIDES_USE = 9; #region create triangles Point[] pointsTheta = Math2D.GetCircle_Cached(NUMSIDES_TOTAL); var circlePoints = pointsTheta. Select(o => GetCirclePoints(o, arcRadius, arcThickness, sphereRadius)). ToArray(); List <Triangle> triangles = new List <Triangle>(); for (int cntr = 0; cntr < NUMSIDES_USE - 1; cntr++) { triangles.Add(new Triangle(circlePoints[cntr].inner, circlePoints[cntr].outer, circlePoints[cntr + 1].inner)); triangles.Add(new Triangle(circlePoints[cntr].outer, circlePoints[cntr + 1].outer, circlePoints[cntr + 1].inner)); } int i1 = NUMSIDES_USE - 1; int i2 = NUMSIDES_USE; var arrowBase = GetCirclePoints(pointsTheta[i1], arcRadius, arrowThickness, sphereRadius); var arrowTip = GetCirclePoints(pointsTheta[i2], arcRadius, arcThickness * .75, sphereRadius); //NOTE: Not using mid, because that curls the arrow too steeply (looks odd). So using outer as a comprimise between pointing in and pointing straight triangles.Add(new Triangle(arrowBase.inner, circlePoints[i1].inner, arrowTip.outer)); triangles.Add(new Triangle(circlePoints[i1].inner, circlePoints[i1].outer, arrowTip.outer)); triangles.Add(new Triangle(circlePoints[i1].outer, arrowBase.outer, arrowTip.outer)); // It would be more efficient to build the link triangles directly, but a lot more logic ITriangleIndexed[] indexedTriangles = TriangleIndexed.ConvertToIndexed(triangles.ToArray()); #endregion List <Model3D> retVal = new List <Model3D>(); MaterialGroup material = new MaterialGroup(); material.Children.Add(new DiffuseMaterial(new SolidColorBrush(WorldColors.ImpulseEngine_Icon_Color))); material.Children.Add(WorldColors.ImpulseEngine_Icon_Specular); material.Children.Add(WorldColors.ImpulseEngine_Icon_Emissive); foreach (Transform3D transform in GetRotations_Tetrahedron(sphereRadius)) { GeometryModel3D geometry = new GeometryModel3D(); geometry.Material = material; geometry.BackMaterial = material; geometry.Geometry = UtilityWPF.GetMeshFromTriangles(indexedTriangles); geometry.Transform = transform; retVal.Add(geometry); } return(retVal.ToArray()); }
private void BuildTerrain() { // Figure out where the extra ring of points should go double radius = BuildTerrainSprtRadius(_neurons.Select(o => o.Position.ToPoint2D()).ToArray()); // Figure out how many extra points to make int numExtra = BuildTerrainSprtNumExtra(_neurons.Length); // Lay down all the points into a single array _terrainPoints = UtilityCore.Iterate( _neurons.Select(o => o.Position), // first points are the neuron's locations (don't worry about Z right now, they will change each update) Math2D.GetCircle_Cached(numExtra).Select(o => new Point3D(o.X * radius, o.Y * radius, 0)) // tack on a bunch of points around the edge ).ToArray(); // Get the delaunay of these points TriangleIndexed[] triangles = Math2D.GetDelaunayTriangulation(_terrainPoints.Select(o => o.ToPoint2D()).ToArray(), _terrainPoints); // Convert into linked triangles List <TriangleIndexedLinked> trianglesLinked = triangles.Select(o => new TriangleIndexedLinked(o.Index0, o.Index1, o.Index2, o.AllPoints)).ToList(); TriangleIndexedLinked.LinkTriangles_Edges(trianglesLinked, true); _terrainTriangles = trianglesLinked.ToArray(); }
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); }