public double AddQuantity(double amount, bool exactAmountOnly) { lock (_lock) { double actualAmount = amount; // Figure out what should actually be stored double max = _quantityMax_Usable ?? _quantityMax; if (_quantityCurrent + actualAmount > max) { actualAmount = max - _quantityCurrent; } //if (exactAmountOnly && actualAmount != amount) if (exactAmountOnly && !Math1D.IsNearValue(actualAmount, amount)) { actualAmount = 0d; } // Add the value _quantityCurrent += actualAmount; // Exit function return(amount - actualAmount); } }
private void Update_Position_Orbit(double elapsedTime) { //NOTE: This method doesn't try to limit motion inside the boundry rectangle, it just used the boundry to calculate orbit radius double orbitRadius = this.Boundry.Length * .8; Vector3D posVect = this.Position.ToVector(); // Fix position if (Math3D.IsNearZero(posVect)) { posVect = Math3D.GetRandomVector_Spherical_Shell(orbitRadius); } else if (!Math1D.IsNearValue(this.Position.ToVector().LengthSquared, orbitRadius * orbitRadius)) { posVect = posVect.ToUnit() * orbitRadius; } // Figure out how many degrees to turn double circ = Math.PI * orbitRadius * 2; double angle = this.Speed_Position / circ * 360 * elapsedTime; posVect = posVect.GetRotatedVector(_velocityUnit, angle); // using the velocity vector as the axis of rotation this.Position = posVect.ToPoint(); }
public double AddQuantity(IContainer pullFrom, double amount, bool exactAmountOnly) { lock (_lock) { double actualAmount = amount; // See if I can handle that much double max = _quantityMax_Usable ?? _quantityMax; if (_quantityCurrent + actualAmount > max) { actualAmount = max - _quantityCurrent; } if (exactAmountOnly && !Math1D.IsNearValue(actualAmount, amount)) { actualAmount = 0d; } if (actualAmount != 0d) { // Now try to pull that much out of the source container actualAmount -= pullFrom.RemoveQuantity(actualAmount, exactAmountOnly); // Add the value _quantityCurrent += actualAmount; } // Exit function return(amount - actualAmount); } }
private static void DrawImage(Image image, double[] values) { double widthHeight = Math.Sqrt(values.Length); // they should be square int widthHeightInt = widthHeight.ToInt_Round(); if (!Math1D.IsNearValue(widthHeight, widthHeightInt)) { throw new ApplicationException("Expected square images"); } BitmapSource source; //if (isColor) //{ // source = UtilityWPF.GetBitmap_RGB(example, width, height); //} //else //{ source = UtilityWPF.GetBitmap(values, widthHeightInt, widthHeightInt); //} image.Source = source; image.Width = source.PixelWidth; // if this isn't set, the image will take up all of the width, and be huge image.Height = source.PixelHeight; }
internal static double RemoveQuantity(double amount, List <Cargo> cargo) { //NOTE: cargo should be sorted from low density to high density, so the lowest quality material is removed first double current = 0d; while (cargo.Count > 0) { double mass = cargo[0].Density * cargo[0].Volume; if (current + mass < amount || Math1D.IsNearValue(current + mass, amount)) { // Eat this whole piece of cargo current += mass; cargo.RemoveAt(0); } else { // Remove some of this cargo double remainingMass = amount - current; double remainingVolume = remainingMass / cargo[0].Density; cargo[0].Volume -= remainingVolume; current = amount; break; } } // Return how much of the request COULDN'T be filled return(amount - current); }
/// <summary> /// This keeps the cargo hold sorted by density /// NOTE: If volumes change outside of this thread, then this could place cargo in an imperfect order. No real damage, just be aware /// </summary> internal static void Add(List <Cargo> cargoHold, Cargo cargo) { if (cargoHold.Count == 0) { cargoHold.Add(cargo); return; } for (int cntr = 0; cntr < cargoHold.Count; cntr++) { if (cargo.Density < cargoHold[cntr].Density) { // This is less dense, put it here cargoHold.Insert(cntr, cargo); return; } else if (Math1D.IsNearValue(cargo.Density, cargoHold[cntr].Density) && cargo.Volume < cargoHold[cntr].Volume) { // This is the same density, but has less volume, so put it here cargoHold.Insert(cntr, cargo); return; } } // This is more desnse than everything else, put it at the end cargoHold.Add(cargo); }
private double AddQuantity_priv(double amount, bool exactAmountOnly) { double current = GetQuantityCurrent(); double max = GetQuantityMax().Item1; // using the destroyed aware max double actualAmount = amount; // Figure out what should actually be stored if (current + actualAmount > max) { actualAmount = max - current; } if (exactAmountOnly && !Math1D.IsNearValue(actualAmount, amount)) { actualAmount = 0d; } if (actualAmount != 0d) { #region Add it // Ensure that the containers are equalized switch (_ownership) { case ContainerOwnershipType.GroupIsSoleOwner: // Nothing to do break; case ContainerOwnershipType.QuantitiesCanChange: EqualizeContainers(false); break; case ContainerOwnershipType.QuantitiesMaxesCanChange: EqualizeContainers(true); break; default: throw new ApplicationException("Unknown ContainerOwnershipType: " + _ownership.ToString()); } // Add the value evenly for (int cntr = 0; cntr < _containers.Count; cntr++) { if (!_destroyed[cntr]) { _containers[cntr].Item1.QuantityCurrent += actualAmount * _ratios[cntr].Item1; // using the destroyed aware ratio } } // Cache the new value (this is used if sole owner) _current = current + actualAmount; #endregion } // Exit function return(amount - actualAmount); }
//NOTE: There is only an add method. Any cargo added to this converter is burned off over time public bool Add(Cargo cargo) { lock (_lock) { //double sumVolume = this.UsedVolume + cargo.Volume; double sumVolume = _cargo.Sum(o => o.Volume) + cargo.Volume; // inlined this.UsedVolume because of the lock if (sumVolume <= this.MaxVolume || Math1D.IsNearValue(sumVolume, this.MaxVolume)) { ConverterMatterToFuel.Add(_cargo, cargo); return(true); } else { return(false); } } }
/// <summary> /// This is a helper method to know what RemoveQuantity will take (between RemovalMultiple and exactAmountOnly, it /// gets a little complex) /// </summary> public static double GetRemoveAmount(IContainer container, double amount, bool exactAmountOnly) { //NOTE: I couldn't think of a way to make this totally threadsafe without adding more to the IContainer interface that returns all the needed //variables in one shot. But in reality, OnlyRemoveMultiples and RemovalMultiple should change very infrequently if ever double retVal = amount; double quantityCurrent = container.QuantityCurrent; // See if the outgoing flow needs to be restricted if (retVal > quantityCurrent) { retVal = quantityCurrent; } // See if it wants even multiples if (container.OnlyRemoveMultiples) { double removalMultiple = container.RemovalMultiple; if (!Math1D.IsDivisible(retVal, removalMultiple)) { // Remove as many multiples of the requested amount as possible retVal = Math.Floor(retVal / removalMultiple) * removalMultiple; } } // Exact amount if (exactAmountOnly && !Math1D.IsNearValue(retVal, amount)) { retVal = 0d; } // Exit Function return(retVal); }
private Model3D GetModel() { const double SIZE = 4; Model3DGroup retVal = new Model3DGroup(); GeometryModel3D geometry; MaterialGroup material; var rhomb = UtilityWPF.GetRhombicuboctahedron(SIZE, SIZE, SIZE); TriangleIndexed[] triangles; #region X,Y,Z spikes double thickness = .2; double length = SIZE * 1.5; retVal.Children.Add(new BillboardLine3D() { Color = UtilityWPF.ColorFromHex("80" + ChaseColors.X), IsReflectiveColor = false, Thickness = thickness, FromPoint = new Point3D(0, 0, 0), ToPoint = new Point3D(length, 0, 0) }.Model); retVal.Children.Add(new BillboardLine3D() { Color = UtilityWPF.ColorFromHex("80" + ChaseColors.Y), IsReflectiveColor = false, Thickness = thickness, FromPoint = new Point3D(0, 0, 0), ToPoint = new Point3D(0, length, 0) }.Model); retVal.Children.Add(new BillboardLine3D() { Color = UtilityWPF.ColorFromHex("80" + ChaseColors.Z), IsReflectiveColor = false, Thickness = thickness, FromPoint = new Point3D(0, 0, 0), ToPoint = new Point3D(0, 0, length) }.Model); #endregion #region X plates geometry = new GeometryModel3D(); material = new MaterialGroup(); material.Children.Add(new DiffuseMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("80" + ChaseColors.X)))); material.Children.Add(new SpecularMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("70DCE01D")), 5)); geometry.Material = material; geometry.BackMaterial = material; triangles = rhomb.Squares_Orth. SelectMany(o => o). Where(o => o.IndexArray.All(p => Math1D.IsNearValue(Math.Abs(o.AllPoints[p].X * 2), SIZE))). ToArray(); geometry.Geometry = UtilityWPF.GetMeshFromTriangles_IndependentFaces(triangles); retVal.Children.Add(geometry); #endregion #region Y plates geometry = new GeometryModel3D(); material = new MaterialGroup(); material.Children.Add(new DiffuseMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("80" + ChaseColors.Y)))); material.Children.Add(new SpecularMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("702892BF")), 3)); geometry.Material = material; geometry.BackMaterial = material; triangles = rhomb.Squares_Orth. SelectMany(o => o). Where(o => o.IndexArray.All(p => Math1D.IsNearValue(Math.Abs(o.AllPoints[p].Y * 2), SIZE))). ToArray(); geometry.Geometry = UtilityWPF.GetMeshFromTriangles_IndependentFaces(triangles); retVal.Children.Add(geometry); #endregion #region Z plates geometry = new GeometryModel3D(); material = new MaterialGroup(); material.Children.Add(new DiffuseMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("80" + ChaseColors.Z)))); material.Children.Add(new SpecularMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("B0CF1919")), 17)); geometry.Material = material; geometry.BackMaterial = material; triangles = rhomb.Squares_Orth. SelectMany(o => o). Where(o => o.IndexArray.All(p => Math1D.IsNearValue(Math.Abs(o.AllPoints[p].Z * 2), SIZE))). ToArray(); geometry.Geometry = UtilityWPF.GetMeshFromTriangles_IndependentFaces(triangles); retVal.Children.Add(geometry); #endregion #region Base geometry = new GeometryModel3D(); material = new MaterialGroup(); material.Children.Add(new DiffuseMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("305B687A")))); material.Children.Add(new SpecularMaterial(new SolidColorBrush(UtilityWPF.ColorFromHex("507E827A")), 12)); geometry.Material = material; geometry.BackMaterial = material; triangles = UtilityCore.Iterate( rhomb.Squares_Diag.SelectMany(o => o), rhomb.Triangles ).ToArray(); geometry.Geometry = UtilityWPF.GetMeshFromTriangles_IndependentFaces(triangles); retVal.Children.Add(geometry); #endregion return(retVal); }
public virtual void Update_AnyThread(double elapsedTime) { //NOTE: This method doesn't have a lock, so there could be a bit of reentry. But the individual pieces should be ok with that double age = this.Age; long count = Interlocked.Increment(ref _partUpdateCount_AnyThread); #region Fill the converters if (_parts.Containers.ConvertMatterGroup != null && age >= (double)_nextMatterTransferTime) { if (_parts.Containers.ConvertMatterGroup.Transfer()) { this.ShouldRecalcMass_Large = true; } //NOTE: Throwing a min in there, because if I have breakpoints set elsewhere, and resume after awhile, elapsed time will be //huge, and the calculated next transer time will be obscene. In those cases, the odds are good that the bot will be fairly young //so a simple 110% of age should be enough of a safeguard //_nextMatterTransferTime = Math.Min(age * 1.1, age + (elapsedTime * StaticRandom.Next(80, 120))); // no need to spin the processor unnecessarily each tick _nextMatterTransferTime = Math.Min(age * 1.1, age + (elapsedTime * StaticRandom.Next(20, 60))); // no need to spin the processor unnecessarily each tick } #endregion #region Update Parts foreach (int index in UtilityCore.RandomRange(0, _updatableParts_AnyThread.Length)) { int skips = _updatableParts_AnyThread[index].IntervalSkips_AnyThread.Value; // no need to check for null, nulls weren't added to the list if (skips > 0 && count % (skips + 1) != 0) { continue; } _updatableParts_AnyThread[index].Update_AnyThread(elapsedTime + (elapsedTime * skips)); // if skips is greater than zero, then approximate how much time elapsed based on this tick's elapsed time } if (_lifeEvents != null) { _lifeEvents.Update_AnyThread(elapsedTime); } // Detect small change if (_hasMassChangingUpdatables_Small) { // There's a good chance that at least one of the parts changed the ship's mass a little bit this.ShouldRecalcMass_Small = true; } // Detect medium change if (_hasMassChangingUpdatables_Medium && !this.ShouldRecalcMass_Medium) { double?ammoVolumeAtRecalc = (double?)_ammoVolumeAtRecalc; double ammoMassCur = _parts.Containers.AmmoGroup.QuantityCurrent; if (ammoVolumeAtRecalc != null && !Math1D.IsNearValue(ammoVolumeAtRecalc.Value, ammoMassCur)) { this.ShouldRecalcMass_Medium = true; } } #endregion #region Recalc mass if (this.ShouldRecalcMass_Large) { RecalculateMass(); } else if (this.ShouldRecalcMass_Medium && age > (double)_lastMassRecalculateTime + (elapsedTime * 200d)) { RecalculateMass(); } else if (this.ShouldRecalcMass_Small && age > (double)_lastMassRecalculateTime + (elapsedTime * 1000d)) //NOTE: This age check isn't atomic, so multiple threads could theoretically interfere, but I don't think it's worth worrying about (the RecalculateMass method itself is threadsafe) { RecalculateMass(); } #endregion }
private void btnMovePoints_Click(object sender, RoutedEventArgs e) { try { if (!double.TryParse(txtRadius.Text, out double radius)) { MessageBox.Show("Couldn't parse radius as a double", this.Title, MessageBoxButton.OK, MessageBoxImage.Warning); return; } if (!double.TryParse(txtMovePercent.Text, out double percent)) { MessageBox.Show("Couldn't parse percent as a double", this.Title, MessageBoxButton.OK, MessageBoxImage.Warning); return; } percent /= 100d; double calcDist; if (chkCalcDist.IsChecked.Value) { if (!double.TryParse(txtCalcDist.Text, out calcDist)) { MessageBox.Show("Couldn't parse calculation distance as a double", this.Title, MessageBoxButton.OK, MessageBoxImage.Warning); return; } } else { calcDist = GetCalcDistance(GetApproximateCount(_dots, radius), radius); } ClearDebugVisuals(); if (!chkInteriorPoints.IsChecked.Value) { // Snap them to the surface of the sphere SnapToSphere(_dots, radius); } Vector3D[] forces = new Vector3D[_dots.Count]; if (chkInteriorPoints.IsChecked.Value && chkInwardForce.IsChecked.Value) { // Inward Force GetInwardForces(forces, _dots); } if (chkRepulsiveForce.IsChecked.Value) { // Repulsion Force GetRepulsionForces(forces, _dots, calcDist); } // Move the points for (int cntr = 0; cntr < _dots.Count; cntr++) { if (!_dots[cntr].IsStatic) { _dots[cntr].Position += forces[cntr] * percent; } } if (!chkInteriorPoints.IsChecked.Value) { // Now that they've moved, snap them back to the surface of the sphere SnapToSphere(_dots, radius); } if (chkShowForcesAfterMove.IsChecked.Value) { btnCalculateForces_Click(this, new RoutedEventArgs()); } if (chkShowRadius.IsChecked.Value) { #region Show Radius double maxRadius = _dots.Where(o => !o.IsStatic).Max(o => o.Position.ToVector().Length); Visual3D visual = null; if (Math1D.IsNearValue(radius, maxRadius)) { // Draw one green one visual = GetSphereVisual(radius, UtilityWPF.ColorFromHex("1000FF00")); _debugVisuals.Add(visual); _viewport.Children.Add(visual); } else if (maxRadius < radius) { // Small than desired radius visual = GetSphereVisual(maxRadius, UtilityWPF.ColorFromHex("10FF0000")); _debugVisuals.Add(visual); _viewport.Children.Add(visual); visual = GetSphereVisual(radius, UtilityWPF.ColorFromHex("10000000")); _debugVisuals.Add(visual); _viewport.Children.Add(visual); } else { // Larger than desired radius visual = GetSphereVisual(radius, UtilityWPF.ColorFromHex("10000000")); _debugVisuals.Add(visual); _viewport.Children.Add(visual); visual = GetSphereVisual(maxRadius, UtilityWPF.ColorFromHex("10FF0000")); _debugVisuals.Add(visual); _viewport.Children.Add(visual); } #endregion } UpdateReport(); } catch (Exception ex) { MessageBox.Show(ex.ToString(), this.Title, MessageBoxButton.OK, MessageBoxImage.Error); } }
public double RemoveQuantity(double amount, bool exactAmountOnly) { lock (_lock) { double current = GetQuantityCurrent(); double max = GetQuantityMax().Item1; // using the destroyed aware max double actualAmount = amount; // See if I need to restrict the outgoing flow if (actualAmount > current) { actualAmount = current; } //NOTE: Only looking at the whole, not each individual container if (_onlyRemoveMultiples && !Math1D.IsDivisible(actualAmount, _removalMultiple)) { // Remove as many multiples of the requested amount as possible actualAmount = Math.Floor(actualAmount / _removalMultiple) * _removalMultiple; } if (exactAmountOnly && !Math1D.IsNearValue(actualAmount, amount)) { actualAmount = 0d; } if (actualAmount != 0d) { #region Remove it // Ensure that the containers are equalized switch (_ownership) { case ContainerOwnershipType.GroupIsSoleOwner: // Nothing to do break; case ContainerOwnershipType.QuantitiesCanChange: EqualizeContainers(false); break; case ContainerOwnershipType.QuantitiesMaxesCanChange: EqualizeContainers(true); break; default: throw new ApplicationException("Unknown ContainerOwnershipType: " + _ownership.ToString()); } // Remove the value evenly for (int cntr = 0; cntr < _containers.Count; cntr++) { _containers[cntr].Item1.QuantityCurrent -= actualAmount * _ratios[cntr].Item1; // using the destroyed aware ratio } // Cache the new value (this is used if sole owner) _current = current - actualAmount; #endregion } // Exit function return(amount - actualAmount); } }
private double AddQuantity_priv(IContainer pullFrom, double amount, bool exactAmountOnly) { if (pullFrom is ITakesDamage && ((ITakesDamage)pullFrom).IsDestroyed) { return(0d); } double current = GetQuantityCurrent(); double max = GetQuantityMax().Item1; // using the destroyed aware max double actualAmount = amount; // See if I can handle that much if (current + actualAmount > max) { actualAmount = max - current; } if (exactAmountOnly && !Math1D.IsNearValue(actualAmount, amount)) { actualAmount = 0d; } if (actualAmount != 0d) { // Now try to pull that much out of the source container actualAmount -= pullFrom.RemoveQuantity(actualAmount, exactAmountOnly); if (actualAmount != 0d) { #region Add it // Ensure that the containers are equalized switch (_ownership) { case ContainerOwnershipType.GroupIsSoleOwner: // Nothing to do break; case ContainerOwnershipType.QuantitiesCanChange: EqualizeContainers(false); break; case ContainerOwnershipType.QuantitiesMaxesCanChange: EqualizeContainers(true); break; default: throw new ApplicationException("Unknown ContainerOwnershipType: " + _ownership.ToString()); } // Add the value evenly for (int cntr = 0; cntr < _containers.Count; cntr++) { if (!_destroyed[cntr]) { _containers[cntr].Item1.QuantityCurrent += actualAmount * _ratios[cntr].Item1; // using the destroyed aware ratio } } // Cache the new value (this is used if sole owner) _current = current + actualAmount; #endregion } } // Exit function return(amount - actualAmount); }
private void ResetTraining() { _patternStorage = null; panelTrainingImages.Children.Clear(); if (_images.Count == 0) { return; } #region choose images int numImages; if (!int.TryParse(txtTrainCount.Text, out numImages)) { MessageBox.Show("Couldn't parse count as an integer", this.Title, MessageBoxButton.OK, MessageBoxImage.Warning); return; } numImages = Math.Min(_images.Count, numImages); var trainImages = UtilityCore.RandomRange(0, _images.Count, numImages). Select(o => new { File = _images[o], Conv = GetTrainingImage(_images[o], _trainKernel), }). ToArray(); #endregion //_patternStorage = new RandomPatternStorage(); _patternStorage = new Hopfield(IMAGESIZE * IMAGESIZE, 0, 1, .9); #region show thumbnails // Display thumbnails //< !--Run them through a KMeans, then sort in 1D-- > //< !--Show full resolution over the canvas on mouseover-- > //< !--Show full resolution under the canvas on click-- > foreach (var trainImage in trainImages) { double widthHeight = Math.Sqrt(trainImage.Conv.Length); // they should be square int widthHeightInt = widthHeight.ToInt_Round(); if (!Math1D.IsNearValue(widthHeight, widthHeightInt)) { throw new ApplicationException("Expected square images"); } double[] imageConv = trainImage.Conv; imageConv = _patternStorage.Convert_Local_External(imageConv); BitmapSource source; //if (isColor) //{ // source = UtilityWPF.GetBitmap_RGB(example, width, height); //} //else //{ source = UtilityWPF.GetBitmap(imageConv, widthHeightInt, widthHeightInt); //} Image image = new Image() { Source = source, Width = source.PixelWidth, // if this isn't set, the image will take up all of the width, and be huge Height = source.PixelHeight, Margin = new Thickness(8), }; panelTrainingImages.Children.Add(image); } #endregion _patternStorage.AddItems(trainImages.Select(o => o.Conv).ToArray()); }
private void AddPoison(Mineral mineral) { // Try to pop this out of the map if (!_map.RemoveItem(mineral, true)) { // It's already gone return; } double mass = mineral.VolumeInCubicMeters * mineral.Density; // Try to remove the equivalent mass from the cargo bay var vomit = base.CargoBays.RemoveMineral_Mass(mass); if (vomit.Item1 > 0d) { this.ShouldRecalcMass_Large = true; } if (Math1D.IsNearValue(vomit.Item1, mass)) { // There was enough in the cargo bay to balance out the poison return; } mass -= vomit.Item1; // The remaining mass needs to come out of plasma/energy/fuel // The conversion ratios are meant to be lossy when going from mass to energy/fuel/plasma. But when run the other direction, they // become overly ideal, so bump the target mass a bit to account for that mass *= 1.1d; // Plasma is least important, take from that first if (AddPoisonSprtContainer(ref mass, this.Plasma, _itemOptions.MatterToPlasma_ConversionRate)) { // There was enough to cover it return; } // Draw from fuel next if (this.Fuel != null && this.Fuel.QuantityCurrent > 0d) { this.ShouldRecalcMass_Large = true; // fuel is about to be removed, so set this now } if (AddPoisonSprtContainer(ref mass, this.Fuel, _itemOptions.MatterToFuel_ConversionRate)) { // There was enough to cover it return; } // Go after energy as a last resort if (AddPoisonSprtContainer(ref mass, this.Energy, _itemOptions.MatterToEnergy_ConversionRate)) { // There was enough to cover it return; } // If there's nothing left, then just exist. The next time this bot is examined, it will be considered dead }