public void Update_AnyThread(double elapsedTime) { //TODO: Draw from energy (maybe only if non null) //if (_energyTanks.RemoveQuantity(elapsedTime * _volume * _itemOptions.VisionSensorAmountToDraw * ItemOptions.ENERGYDRAWMULT, true) > 0d) //{ // // The energy tank didn't have enough // //NOTE: To be clean, I should set the neuron outputs to zero, but anything pulling from them should be checking this // //anyway. So save the processor (also, because of threading, setting them to zero isn't as atomic as this property) // _isOn = false; // return; //} //_isOn = true; Point linear = Math3D.GetCenter(_neurons_linear.Select(o => Tuple.Create(o.Position, o.Value)).ToArray()).ToPoint2D(); //TODO: Look at the desired rotation // // Need to store the point that is being rotated around // // Basically a unit vector that holds the current location within a circle, then use radius to calculate the center of rotation for this tick _mousePlate.CurrentPoint2D = linear; }
private const double MOVEPERSTEPPERCENT = 1d; // this seems to be stable with 100%, if nessassary, drop it down a bit so that parts don't move as far each step #endregion //TODO: Make a better version, probably a combination of pulling in and separating public static void PullInCrude(out bool changed, PartSeparator_Part[] parts) { // Figure out the max radius double[] sizes = parts.Select(o => (o.Size.X + o.Size.Y + o.Size.Z) / 3d).ToArray(); double largestPart = sizes.Max(); double maxRadius = largestPart * 8d; double maxRadiusSquare = maxRadius * maxRadius; Point3D center = Math3D.GetCenter(parts.Select(o => Tuple.Create(o.Position, o.Mass)).ToArray()); changed = false; for (int cntr = 0; cntr < parts.Length; cntr++) { Vector3D offset = parts[cntr].Position - center; //NOTE: This is just going to the center of the part, it's not considering the extents of the part (this method IS called crude) if (offset.LengthSquared < maxRadiusSquare) { continue; } // Pull it straight in double difference = offset.Length - maxRadius; offset.Normalize(); offset *= difference * -1d; parts[cntr].Position += offset; //NOTE: I'm not going to change the center of mass changed = true; } }
/// <summary> /// This finds the best point by converting neuron positions/values into a hilly terrain, and taking a contour plot. /// The middle of the biggest polygon is the chosen point. /// </summary> private void Update_Contour() { const double CONTOURHEIGHT = .6667d; #region Set heights double maxHeight = 0; for (int cntr = 0; cntr < _neurons.Length; cntr++) { _terrainPoints[cntr].Z = _neurons[cntr].Value * 100; if (_terrainPoints[cntr].Z > maxHeight) { maxHeight = _terrainPoints[cntr].Z; } } for (int cntr = 0; cntr < _terrainTriangles.Length; cntr++) { _terrainTriangles[cntr].PointsChanged(); } double height = maxHeight * CONTOURHEIGHT; #endregion Triangle plane = new Triangle(new Point3D(-1, 0, height), new Point3D(1, 0, height), new Point3D(0, 1, height)); // normal needs to point up // Get the contour polygons var polys = Math3D.GetIntersection_Mesh_Plane(_terrainTriangles, plane); if (polys == null || polys.Length == 0) { // Nothing, don't move _mousePlate.CurrentPoint2D = new Point(0, 0); return; } else if (polys.Length == 1) { // Just one polygon, no need to take the expense of calculating volume _mousePlate.CurrentPoint2D = Math3D.GetCenter(polys[0].Polygon3D).ToPoint2D(); return; } // Find the polygon with the highest volume var topPoly = polys. Select(o => new { Poly = o, Volume = o.GetVolumeAbove() }). OrderByDescending(o => o.Volume). First(); // Go to the center of this polygon _mousePlate.CurrentPoint2D = Math3D.GetCenter(topPoly.Poly.Polygon3D).ToPoint2D(); }
/// <summary> /// This is a helper method to turn som node positions into points to pass to AddStaticItems() /// </summary> public static IEnumerable <Tuple <ISOMInput, Point3D> > GetSOMNodeStaticPositions(SOMNode node, SOMNode[] allNodes, double innerRadius) { // Convert to Point3D var initial = allNodes. Select(o => { Vector3D position = new Vector3D(); if (o.Position.Size >= 1) { position.X = o.Position[0]; } if (o.Position.Size >= 2) { position.Y = o.Position[1]; } if (o.Position.Size >= 3) { position.Z = o.Position[2]; } return(Tuple.Create(o, position, position.Length)); }). OrderBy(o => o.Item3). ToArray(); // Find the closest one (that isn't the one passed in) var firstNonZero = initial. Where(o => o.Item1.Token != node.Token). FirstOrDefault(o => !o.Item3.IsNearZero()); double scale = 1d; if (firstNonZero != null) { scale = (innerRadius * 1.25) / firstNonZero.Item3; } // Make sure they are spaced properly var scaled = initial. Select(o => Tuple.Create(o.Item1, (o.Item2 * scale).ToPoint())). ToArray(); // These need to be centered over the origin, because the points will try to drift to the center Point3D center = Math3D.GetCenter(scaled.Select(o => o.Item2)); Vector3D offset = new Vector3D(-center.X, -center.Y, -center.Z); return(scaled. Select(o => Tuple.Create((ISOMInput)o.Item1, o.Item2 + offset)). ToArray()); }
private static Vector3D[] GetForces(SketchDots sketches, bool useOutput, double mult) { // Give them a very slight pull toward the origin so that the cloud doesn't drift away Point3D center = Math3D.GetCenter(sketches.Sketches.Select(o => o.Position)); double centerMult = mult * -5; Vector3D centerPullForce = center.ToVector() * centerMult; Vector3D[] retVal = Enumerable.Range(0, sketches.Sketches.Length). Select(o => centerPullForce). ToArray(); // Figure out which set of distances to use var distances = useOutput ? sketches.Distances_Output : sketches.Distances_Input; foreach (var link in distances) { // Spring from 1 to 2 Vector3D spring = sketches.Sketches[link.Item2].Position - sketches.Sketches[link.Item1].Position; double springLength = spring.Length; double difference = link.Item3 - springLength; difference *= mult; if (Math3D.IsNearZero(springLength)) { spring = Math3D.GetRandomVector_Spherical_Shell(Math.Abs(difference)); } else { spring = spring.ToUnit() * Math.Abs(difference); } if (difference > 0) { // Gap needs to be bigger, push them away retVal[link.Item1] -= spring; retVal[link.Item2] += spring; } else if (difference < 0) { // Close the gap retVal[link.Item1] += spring; retVal[link.Item2] -= spring; } } return(retVal); }
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)); }
/// <summary> /// This is the average of the 4 points /// </summary> public Point3D GetCenterPoint() { return(Math3D.GetCenter(new[] { this.AllPoints[this.Index0], this.AllPoints[this.Index1], this.AllPoints[this.Index2], this.AllPoints[this.Index3] })); }
private static Model3DGroup GetModel_Klinth(WeaponSpikeBallDNA dna, WeaponSpikeBallDNA finalDNA, WeaponMaterialCache materials) { Model3DGroup retVal = new Model3DGroup(); var from = dna.KeyValues; var to = finalDNA.KeyValues; double spikeLength = WeaponDNA.GetKeyValue("spikeLength", from, to, StaticRandom.NextPercent(dna.Radius * 1.1d, .05)); double ballRadius = dna.Radius; double spikeRadius = WeaponDNA.GetKeyValue("spikeRadius", from, to, StaticRandom.NextPercent(dna.Radius * .2, .1)); var color = WeaponMaterialCache.GetKlinth(dna.MaterialsForCustomizable); finalDNA.MaterialsForCustomizable = color.Item3; GeometryModel3D geometry; #region Ball geometry = new GeometryModel3D(); geometry.Material = color.Item1; geometry.BackMaterial = color.Item1; Icosidodecahedron ball = UtilityWPF.GetIcosidodecahedron(ballRadius); geometry.Geometry = UtilityWPF.GetMeshFromTriangles_IndependentFaces(ball.AllTriangles); retVal.Children.Add(geometry); #endregion #region Spikes // Put a spike through the center of each pentagon foreach (Vector3D spikeLocation in ball.PentagonPolys.Select(o => Math3D.GetCenter(o.Select(p => ball.AllPoints[p])))) { geometry = new GeometryModel3D(); geometry.Material = color.Item2; geometry.BackMaterial = color.Item2; RotateTransform3D transform = new RotateTransform3D(new QuaternionRotation3D(Math3D.GetRotation(new Vector3D(0, 0, 1), spikeLocation))); // the tube builds along z List <TubeRingBase> rings = new List <TubeRingBase>(); double spikeLengthMid = spikeLength * .8d; rings.Add(new TubeRingRegularPolygon(0, false, spikeRadius, spikeRadius, false)); rings.Add(new TubeRingRegularPolygon(spikeLengthMid, false, spikeRadius, spikeRadius, false)); rings.Add(new TubeRingDome(spikeLength - spikeLengthMid, false, 3)); geometry.Geometry = UtilityWPF.GetMultiRingedTube(9, rings, false, false, transform); retVal.Children.Add(geometry); } #endregion return(retVal); }
private static Model3DGroup GetModel_Composite(WeaponSpikeBallDNA dna, WeaponSpikeBallDNA finalDNA, WeaponMaterialCache materials) { Model3DGroup retVal = new Model3DGroup(); Random rand = StaticRandom.GetRandomForThread(); var from = dna.KeyValues; var to = finalDNA.KeyValues; double spikeOrthLength = WeaponDNA.GetKeyValue("spikeOrthLength", from, to, rand.NextPercent(dna.Radius * 1.4d, .1)); double spikeDiagLength = WeaponDNA.GetKeyValue("spikeDiagLength", from, to, rand.NextPercent(dna.Radius * 1.15d, .05)); double ballRadius = dna.Radius; double spikeOrthRadius = WeaponDNA.GetKeyValue("spikeOrthRadius", from, to, rand.NextPercent(dna.Radius * .5, .1)); double spikeDiagRadius = WeaponDNA.GetKeyValue("spikeDiagRadius", from, to, rand.NextPercent(dna.Radius * .5, .1)); double ballRadiusDepth = ballRadius * .1; //this is how far the triangle parts of the ball sink in var color = WeaponMaterialCache.GetComposite(dna.MaterialsForCustomizable); finalDNA.MaterialsForCustomizable = color.Item4; GeometryModel3D geometry; #region Ball - outer geometry = new GeometryModel3D(); geometry.Material = color.Item1; geometry.BackMaterial = color.Item1; Rhombicuboctahedron ball = UtilityWPF.GetRhombicuboctahedron(ballRadius * 2, ballRadius * 2, ballRadius * 2); TriangleIndexed[] usedTriangles = UtilityCore.Iterate( ball.Squares_Orth.SelectMany(o => o), ball.Squares_Diag.SelectMany(o => o), GetModel_Composite_SquareSides(ball, ballRadiusDepth * 1.1) // this builds plates that go toward the center of the ball, because the triangles are indented ).ToArray(); geometry.Geometry = UtilityWPF.GetMeshFromTriangles_IndependentFaces(usedTriangles); retVal.Children.Add(geometry); #endregion #region Ball - inner geometry = new GeometryModel3D(); geometry.Material = color.Item2; geometry.BackMaterial = color.Item2; // Use the triangles, but suck them in a bit geometry.Geometry = UtilityWPF.GetMeshFromTriangles_IndependentFaces(GetModel_Composite_IndentedTriangles(ball, ballRadiusDepth)); retVal.Children.Add(geometry); #endregion #region Spikes var spikeLocations = UtilityCore.Iterate(ball.SquarePolys_Orth.Select(o => Tuple.Create(true, o)), ball.SquarePolys_Diag.Select(o => Tuple.Create(false, o))). Select(o => new { IsOrth = o.Item1, Center = Math3D.GetCenter(o.Item2.Select(p => ball.AllPoints[p])).ToVector() }); // Put a spike through the center of each square foreach (var spikeLocation in spikeLocations) { geometry = new GeometryModel3D(); geometry.Material = color.Item3; geometry.BackMaterial = color.Item3; RotateTransform3D transform = new RotateTransform3D(new QuaternionRotation3D(Math3D.GetRotation(new Vector3D(0, 0, 1), spikeLocation.Center))); // the tube builds along z List <TubeRingBase> rings = new List <TubeRingBase>(); double spikeLengthActual = spikeLocation.IsOrth ? spikeOrthLength : spikeDiagLength; double spikeRadiusActual = spikeLocation.IsOrth ? spikeOrthRadius : spikeDiagRadius; rings.Add(new TubeRingRegularPolygon(0, false, spikeRadiusActual, spikeRadiusActual, false)); rings.Add(new TubeRingPoint(spikeLengthActual, false)); geometry.Geometry = UtilityWPF.GetMultiRingedTube(9, rings, true, false, transform); retVal.Children.Add(geometry); } #endregion return(retVal); }
private static Tuple <Dot, Vector3D>[] GetForces(DotVisuals dots, bool useOutput, double mult) { // Figure out which set of distances to use var distances = useOutput ? dots.Distances_Output : dots.Distances_Input; #region Calculate forces Tuple <Dot, Vector3D>[] forces = distances. //AsParallel(). //TODO: if distances.Length > threshold, do this in parallel SelectMany(o => { // Spring from 1 to 2 Vector3D spring = o.Item2.Position - o.Item1.Position; double springLength = spring.Length; double difference = o.Item3 - springLength; difference *= mult; if (Math1D.IsNearZero(springLength)) { spring = Math3D.GetRandomVector_Spherical_Shell(Math.Abs(difference)); } else { spring = spring.ToUnit() * Math.Abs(difference); } if (difference > 0) { // Gap needs to be bigger, push them away (default is closing the gap) spring = -spring; } return(new[] { Tuple.Create(o.Item1, spring), Tuple.Create(o.Item2, -spring) }); }). ToArray(); #endregion // Give them a very slight pull toward the origin so that the cloud doesn't drift away Point3D center = Math3D.GetCenter(dots.Dots.Select(o => o.Position)); double centerMult = mult * -5; Vector3D centerPullForce = center.ToVector() * centerMult; // Group by dot var grouped = forces. GroupBy(o => o.Item1.Token); return(grouped. Select(o => { Vector3D sum = centerPullForce; Dot dot = null; foreach (var force in o) { dot = force.Item1; sum += force.Item2; } return Tuple.Create(dot, sum); }). ToArray()); }