private void RecalculateFitnessFunctionValues() { var minFitnessFunctionValue = _population.Individuals[0].FitnessFunctionValue; float fitnessFunctionSum = 0; for (int i = 1; i < _population.Count; i++) { if (_population.Individuals[i].FitnessFunctionValue < minFitnessFunctionValue) { minFitnessFunctionValue = _population.Individuals[i].FitnessFunctionValue; } } for (int i = 0; i < _population.Count; i++) { _population.Individuals[i].FitnessFunctionValue = _population.Individuals[i].FitnessFunctionValue + 2 * MathF.Abs(minFitnessFunctionValue); fitnessFunctionSum += _population.Individuals[i].FitnessFunctionValue; } _population.FitnessFunctionSum = fitnessFunctionSum; }
private static (Size, Rectangle) CalculateCropRectangle( Size source, ResizeOptions options, int width, int height) { if (width <= 0 || height <= 0) { return(new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height)); } float ratio; int sourceWidth = source.Width; int sourceHeight = source.Height; int destinationX = 0; int destinationY = 0; int destinationWidth = width; int destinationHeight = height; // Fractional variants for preserving aspect ratio. float percentHeight = MathF.Abs(height / (float)sourceHeight); float percentWidth = MathF.Abs(width / (float)sourceWidth); if (percentHeight < percentWidth) { ratio = percentWidth; if (options.CenterCoordinates.Any()) { float center = -(ratio * sourceHeight) * options.CenterCoordinates.ToArray()[1]; destinationY = (int)MathF.Round(center + (height / 2F)); if (destinationY > 0) { destinationY = 0; } if (destinationY < (int)MathF.Round(height - (sourceHeight * ratio))) { destinationY = (int)MathF.Round(height - (sourceHeight * ratio)); } } else { switch (options.Position) { case AnchorPositionMode.Top: case AnchorPositionMode.TopLeft: case AnchorPositionMode.TopRight: destinationY = 0; break; case AnchorPositionMode.Bottom: case AnchorPositionMode.BottomLeft: case AnchorPositionMode.BottomRight: destinationY = (int)MathF.Round(height - (sourceHeight * ratio)); break; default: destinationY = (int)MathF.Round((height - (sourceHeight * ratio)) / 2F); break; } } destinationHeight = (int)MathF.Ceiling(sourceHeight * percentWidth); } else { ratio = percentHeight; if (options.CenterCoordinates.Any()) { float center = -(ratio * sourceWidth) * options.CenterCoordinates.First(); destinationX = (int)MathF.Round(center + (width / 2F)); if (destinationX > 0) { destinationX = 0; } if (destinationX < (int)MathF.Round(width - (sourceWidth * ratio))) { destinationX = (int)MathF.Round(width - (sourceWidth * ratio)); } } else { switch (options.Position) { case AnchorPositionMode.Left: case AnchorPositionMode.TopLeft: case AnchorPositionMode.BottomLeft: destinationX = 0; break; case AnchorPositionMode.Right: case AnchorPositionMode.TopRight: case AnchorPositionMode.BottomRight: destinationX = (int)MathF.Round(width - (sourceWidth * ratio)); break; default: destinationX = (int)MathF.Round((width - (sourceWidth * ratio)) / 2F); break; } } destinationWidth = (int)MathF.Ceiling(sourceWidth * percentHeight); } return(new Size(width, height), new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight)); }
private static (Size, Rectangle) CalculateBoxPadRectangle( Size source, ResizeOptions options, int width, int height) { if (width <= 0 || height <= 0) { return(new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height)); } int sourceWidth = source.Width; int sourceHeight = source.Height; // Fractional variants for preserving aspect ratio. float percentHeight = MathF.Abs(height / (float)sourceHeight); float percentWidth = MathF.Abs(width / (float)sourceWidth); int boxPadHeight = height > 0 ? height : (int)MathF.Round(sourceHeight * percentWidth); int boxPadWidth = width > 0 ? width : (int)MathF.Round(sourceWidth * percentHeight); // Only calculate if upscaling. if (sourceWidth < boxPadWidth && sourceHeight < boxPadHeight) { int destinationX; int destinationY; int destinationWidth = sourceWidth; int destinationHeight = sourceHeight; width = boxPadWidth; height = boxPadHeight; switch (options.Position) { case AnchorPositionMode.Left: destinationY = (height - sourceHeight) / 2; destinationX = 0; break; case AnchorPositionMode.Right: destinationY = (height - sourceHeight) / 2; destinationX = width - sourceWidth; break; case AnchorPositionMode.TopRight: destinationY = 0; destinationX = width - sourceWidth; break; case AnchorPositionMode.Top: destinationY = 0; destinationX = (width - sourceWidth) / 2; break; case AnchorPositionMode.TopLeft: destinationY = 0; destinationX = 0; break; case AnchorPositionMode.BottomRight: destinationY = height - sourceHeight; destinationX = width - sourceWidth; break; case AnchorPositionMode.Bottom: destinationY = height - sourceHeight; destinationX = (width - sourceWidth) / 2; break; case AnchorPositionMode.BottomLeft: destinationY = height - sourceHeight; destinationX = 0; break; default: destinationY = (height - sourceHeight) / 2; destinationX = (width - sourceWidth) / 2; break; } return(new Size(width, height), new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight)); } // Switch to pad mode to downscale and calculate from there. return(CalculatePadRectangle(source, options, width, height)); }
private static float Diff(float a, float b) => MathF.Abs((a * 65535F) - (b * 65535F));
GraphicsMemoryRegion <GraphicsResource> CreateTexture3DRegion(GraphicsContext graphicsContext, GraphicsBuffer textureStagingBuffer, bool isQuickAndDirty) { var textureWidth = isQuickAndDirty ? 64u : 256u; var textureHeight = isQuickAndDirty ? 64u : 256u; var textureDepth = isQuickAndDirty ? (ushort)64 : (ushort)256; var textureDz = textureWidth * textureHeight; var texturePixels = textureDz * textureDepth; var texture3D = graphicsContext.Device.MemoryAllocator.CreateTexture(GraphicsTextureKind.ThreeDimensional, GraphicsResourceCpuAccess.None, textureWidth, textureHeight, textureDepth, texelFormat: TexelFormat.R8G8B8A8_UNORM); var texture3DRegion = texture3D.Allocate(texture3D.Size, alignment: 4); var pTextureData = textureStagingBuffer.Map <uint>(in texture3DRegion); var random = new Random(Seed: 1); var isOnBlurring = true; // start with random speckles for (uint n = 0; n < texturePixels; n++) { // convert n to indices float x = n % textureWidth; float y = n % textureDz / textureWidth; float z = n / textureDz; // convert indices to fractions in the range [0, 1) x /= textureWidth; y /= textureHeight; z /= textureHeight; // make x,z relative to texture center x -= 0.5f; z -= 0.5f; // get radius from center, clamped to 0.5 var radius = MathF.Abs(x); // MathF.Sqrt(x * x + z * z); if (radius > 0.5f) { radius = 0.5f; } // scale as 1 in center, tapering off to the edge var scale = 2 * MathF.Abs(0.5f - radius); // random value scaled by the above var rand = (float)random.NextDouble(); if (isOnBlurring && (rand < 0.99)) { rand = 0; } uint value = (byte)(rand * scale * 255); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } if (isOnBlurring) { // now smear them out to smooth smoke splotches var dy = textureWidth; var dz = dy * textureHeight; var falloffFactor = _isQuickAndDirty ? 0.9f : 0.95f; for (var z = 0; z < textureDepth; z++) { for (var y = 0; y < textureHeight; y++) { for (var x = 1; x < textureWidth; x++) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - 1] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n - 1] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } for (var x = (int)textureWidth - 2; x >= 0; x--) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + 1] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n + 1] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } } } for (var z = 0; z < textureDepth; z++) { for (var x = 0; x < textureWidth; x++) { for (var y = 1; y < textureHeight; y++) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - dy] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n - dy] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } for (var y = 0; y <= 0; y++) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - dy + dz] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n - dy + dz] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } for (var y = 1; y < textureHeight; y++) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - dy] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n - dy] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } for (var y = (int)textureHeight - 2; y >= 0; y--) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + dy] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n + dy] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } for (var y = (int)textureHeight - 1; y >= (int)textureHeight - 1; y--) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + dy - dz] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n + dy - dz] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } for (var y = (int)textureHeight - 2; y >= 0; y--) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + dy] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n + dy] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } } } for (var y = 0; y < textureHeight; y++) { for (var x = 0; x < textureWidth; x++) { for (var z = 1; z < textureDepth; z++) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n - dz] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n - 1] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } for (var z = (int)textureDepth - 0; z >= 0; z--) { var n = x + (y * dy) + (z * dz); if ((pTextureData[n] & 0xFF) < falloffFactor * (pTextureData[n + dz] & 0xFF)) { uint value = (byte)(falloffFactor * (pTextureData[n + 1] & 0xFF)); pTextureData[n] = (uint)(value | (value << 8) | (value << 16) | (value << 24)); } } } } } textureStagingBuffer.UnmapAndWrite(in texture3DRegion); graphicsContext.Copy(texture3D, textureStagingBuffer); return(texture3DRegion); }
public static bool IsZero(float num) { return(MathF.Abs(num) < ZeroTolerance); }
/// <inheritdoc/> protected override void OnFrameApply( ImageFrame <TPixel> source, Rectangle sourceRectangle, Configuration configuration) { int brushSize = this.definition.BrushSize; if (brushSize <= 0 || brushSize > source.Height || brushSize > source.Width) { throw new ArgumentOutOfRangeException(nameof(brushSize)); } int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int maxY = endY - 1; int maxX = endX - 1; int radius = brushSize >> 1; int levels = this.definition.Levels; using (Buffer2D <TPixel> targetPixels = configuration.MemoryAllocator.Allocate2D <TPixel>(source.Size())) { source.CopyTo(targetPixels); var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); ParallelHelper.IterateRows( workingRect, configuration, rows => { for (int y = rows.Min; y < rows.Max; y++) { Span <TPixel> sourceRow = source.GetPixelRowSpan(y); Span <TPixel> targetRow = targetPixels.GetRowSpan(y); for (int x = startX; x < endX; x++) { int maxIntensity = 0; int maxIndex = 0; var intensityBin = new int[levels]; var redBin = new float[levels]; var blueBin = new float[levels]; var greenBin = new float[levels]; for (int fy = 0; fy <= radius; fy++) { int fyr = fy - radius; int offsetY = y + fyr; offsetY = offsetY.Clamp(0, maxY); Span <TPixel> sourceOffsetRow = source.GetPixelRowSpan(offsetY); for (int fx = 0; fx <= radius; fx++) { int fxr = fx - radius; int offsetX = x + fxr; offsetX = offsetX.Clamp(0, maxX); var vector = sourceOffsetRow[offsetX].ToVector4(); float sourceRed = vector.X; float sourceBlue = vector.Z; float sourceGreen = vector.Y; int currentIntensity = (int)MathF.Round( (sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); intensityBin[currentIntensity]++; blueBin[currentIntensity] += sourceBlue; greenBin[currentIntensity] += sourceGreen; redBin[currentIntensity] += sourceRed; if (intensityBin[currentIntensity] > maxIntensity) { maxIntensity = intensityBin[currentIntensity]; maxIndex = currentIntensity; } } float red = MathF.Abs(redBin[maxIndex] / maxIntensity); float green = MathF.Abs(greenBin[maxIndex] / maxIntensity); float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); ref TPixel pixel = ref targetRow[x]; pixel.FromVector4( new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); } } } }); Buffer2D <TPixel> .SwapOrCopyContent(source.PixelBuffer, targetPixels); } }
/// <summary> /// Run a single cart-pole simulation/trial on the given black box, and with the given initial model state. /// </summary> /// <param name="box">The black box (neural net) to evaluate.</param> /// <param name="cartPos">Cart position on the track.</param> /// <param name="poleAngle">Pole angle in radians.</param> /// <returns>Fitness score.</returns> public float RunTrial( IBlackBox <double> box, float cartPos, float poleAngle) { // Reset black box state. box.Reset(); // Reset model state. _physics.ResetState(cartPos, poleAngle); // Get a local variable ref to the internal model state array. float[] state = _physics.State; // Get the blackbox input and output spans. var inputs = box.Inputs.Span; var outputs = box.Outputs.Span; // Run the cart-pole simulation. int timestep = 0; for (; timestep < _maxTimesteps; timestep++) { // Provide model state to the black box inputs (normalised to +-1.0). inputs[0] = 1.0; // Bias input. inputs[1] = state[0] * __TrackLengthHalf_Reciprocal; // Cart X position range is +-__TrackLengthHalf; here we normalize to [-1,1]. inputs[2] = state[2] * __MaxPoleAngle_Reciprocal; // Pole angle range is +-__MaxPoleAngle radians; here we normalize to [-1,1]. // Activate the network. box.Activate(); // Read the output to determine the force to be applied to the cart by the controller. float force = (float)(outputs[0] - 0.5) * 2f; ClipForce(ref force); force *= __MaxForce; // Update model state, i.e. move the model forward by one timestep. _physics.Update(force); // Check for failure state. I.e. has the cart run off the ends of the track, or has the pole // angle exceeded the defined threshold. if (MathF.Abs(state[0]) > __TrackLengthHalf || MathF.Abs(state[2]) > __MaxPoleAngle) { break; } } // Fitness is given by the combination of four fitness components: // 1) Amount of simulation time that elapsed before the pole angle and/or cart position threshold was exceeded. Max score is 80 if the // end of the trial is reached without exceeding any thresholds. // 2) Cart position component. Max fitness of 1.0 for a cart position of zero (i.e. the cart is in the middle of the track range); // 3) Pole angle component. Max fitness of 9.5 for a pole angle of 0 degrees (vertical pole). // 4) Pole angular velocity component. Maximum fitness 9.5 for a zero velocity. // // Therefore the maximum possible fitness is 100.0, when the pole is perfectly stationary, and the cart is in the middle of the track. float fitness = (timestep * _maxTimesteps_Reciprocal * 80f) + (1f - (MathF.Min(MathF.Abs(state[0]), __TrackLengthHalf) * __TrackLengthHalf_Reciprocal)) + ((1f - (MathF.Min(MathF.Abs(state[2]), __MaxPoleAngle) * __MaxPoleAngle_Reciprocal)) * 9.5f) + ((1f - MathF.Min(MathF.Abs(state[3]), 1f)) * 9.5f); return(fitness); }
protected override void OnPaint(PaintEventArgs e) { base.OnPaint(e); // Paint checkered background if (this.backBrush != null) { Point offset = this.GetDisplayPos(Vector2.Zero); this.backBrush.ResetTransform(); this.backBrush.TranslateTransform(offset.X, offset.Y); e.Graphics.FillRectangle(this.backBrush, this.ClientRectangle); } // Draw image outline if (this.image != null) { Rectangle outlineRect = this.GetDisplayRect(new Rect(this.targetPixmap.Width, this.targetPixmap.Height)); // Offset the rect, so that it won't overlap the actual image area outlineRect.Inflate(1, 1); e.Graphics.DrawRectangle( Pens.Red, outlineRect); } // Draw target image if (this.image != null) { bool isIntScaling = MathF.Abs(MathF.RoundToInt(this.scaleFactor) - this.scaleFactor) < 0.0001f; // Choose filtering mode depending on whether we're scaling by a full Nx factor e.Graphics.InterpolationMode = isIntScaling ? InterpolationMode.NearestNeighbor : InterpolationMode.HighQualityBicubic; e.Graphics.PixelOffsetMode = isIntScaling ? PixelOffsetMode.Half : PixelOffsetMode.None; Rectangle scrolledImageRect = this.imageRect; scrolledImageRect.X += this.AutoScrollPosition.X; scrolledImageRect.Y += this.AutoScrollPosition.Y; e.Graphics.DrawImage(this.image, scrolledImageRect); e.Graphics.InterpolationMode = InterpolationMode.Default; e.Graphics.PixelOffsetMode = PixelOffsetMode.Default; } // Draw rect outlines and indices if (this.targetPixmap != null && this.targetPixmap.Atlas != null) { for (int i = 0; i < this.targetPixmap.Atlas.Count; i++) { Rect atlasRect = this.targetPixmap.Atlas[i]; Rectangle displayRect = this.GetDisplayRect(atlasRect); e.Graphics.DrawRectangle( this.RectPen, displayRect); bool isHoveredOrSelected = (this.hoveredRectIndex == i || this.selectedRectIndex == i); if (this.rectNumbering == PixmapNumberingStyle.All || (this.rectNumbering == PixmapNumberingStyle.Hovered && isHoveredOrSelected)) { this.DrawRectIndex(e.Graphics, displayRect, i); } } // Draw selected outline on top of all others if (this.selectedRectIndex != -1) { Rect atlasRect = this.GetAtlasRect(this.selectedRectIndex); Rectangle displayRect = this.GetDisplayRect(atlasRect); e.Graphics.DrawRectangle( this.SelectedRectPen, displayRect); } } if (this.PaintContentOverlay != null) { this.PaintContentOverlay(this, e); } }
public void Update() { UpdateReagents(); var curTime = _gameTiming.CurTime; if (ForceUpdate) { ForceUpdate = false; } else if (curTime < (_lastCycle + _cycleDelay)) { if (_updateSpriteAfterUpdate) { UpdateSprite(); } return; } _lastCycle = curTime; // Weeds like water and nutrients! They may appear even if there's not a seed planted. if (WaterLevel > 10 && NutritionLevel > 2 && _random.Prob(Seed == null ? 0.05f : 0.01f)) { WeedLevel += 1 * HydroponicsSpeedMultiplier * WeedCoefficient; if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } // There's a chance for a weed explosion to happen if weeds take over. // Plants that are themselves weeds (WeedTolerance > 8) are unaffected. if (WeedLevel >= 10 && _random.Prob(0.1f)) { if (Seed == null || WeedLevel >= Seed.WeedTolerance + 2) { WeedInvasion(); } } // If we have no seed planted, or the plant is dead, stop processing here. if (Seed == null || Dead) { if (_updateSpriteAfterUpdate) { UpdateSprite(); } return; } // There's a small chance the pest population increases. // Can only happen when there's a live seed planted. if (_random.Prob(0.01f)) { PestLevel += 0.5f * HydroponicsSpeedMultiplier; if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } // Advance plant age here. if (SkipAging > 0) { SkipAging--; } else { if (_random.Prob(0.8f)) { Age += (int)(1 * HydroponicsSpeedMultiplier); } _updateSpriteAfterUpdate = true; } // Nutrient consumption. if (Seed.NutrientConsumption > 0 && NutritionLevel > 0 && _random.Prob(0.75f)) { NutritionLevel -= MathF.Max(0f, Seed.NutrientConsumption * HydroponicsSpeedMultiplier); if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } // Water consumption. if (Seed.WaterConsumption > 0 && WaterLevel > 0 && _random.Prob(0.75f)) { WaterLevel -= MathF.Max(0f, Seed.NutrientConsumption * HydroponicsConsumptionMultiplier * HydroponicsSpeedMultiplier); if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } var healthMod = _random.Next(1, 3) * HydroponicsSpeedMultiplier; // Make sure the plant is not starving. if (_random.Prob(0.35f)) { if (NutritionLevel > 2) { Health += healthMod; } else { AffectGrowth(-1); Health -= healthMod; } if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } // Make sure the plant is not thirsty. if (_random.Prob(0.35f)) { if (WaterLevel > 10) { Health += healthMod; } else { AffectGrowth(-1); Health -= healthMod; } if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } var tileAtmos = Owner.Transform.Coordinates.GetTileAtmosphere(); var environment = tileAtmos?.Air ?? GasMixture.SpaceGas; if (Seed.ConsumeGasses.Count > 0) { _missingGas = 0; foreach (var(gas, amount) in Seed.ConsumeGasses) { if (environment.GetMoles(gas) < amount) { _missingGas++; continue; } environment.AdjustMoles(gas, -amount); } if (_missingGas > 0) { Health -= _missingGas * HydroponicsSpeedMultiplier; if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } } // Seed pressure resistance. var pressure = environment.Pressure; if (pressure < Seed.LowPressureTolerance || pressure > Seed.HighPressureTolerance) { Health -= healthMod; ImproperPressure = true; if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } else { ImproperPressure = false; } // Seed ideal temperature. if (MathF.Abs(environment.Temperature - Seed.IdealHeat) > Seed.HeatTolerance) { Health -= healthMod; ImproperHeat = true; if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } else { ImproperHeat = false; } // Gas production. var exudeCount = Seed.ExudeGasses.Count; if (exudeCount > 0) { foreach (var(gas, amount) in Seed.ExudeGasses) { environment.AdjustMoles(gas, MathF.Max(1f, MathF.Round((amount * MathF.Round(Seed.Potency)) / exudeCount))); } } // Toxin levels beyond the plant's tolerance cause damage. // They are, however, slowly reduced over time. if (Toxins > 0) { var toxinUptake = MathF.Max(1, MathF.Round(Toxins / 10f)); if (Toxins > Seed.ToxinsTolerance) { Health -= toxinUptake; } Toxins -= toxinUptake; if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } // Weed levels. if (PestLevel > 0) { // TODO: Carnivorous plants? if (PestLevel > Seed.PestTolerance) { Health -= HydroponicsSpeedMultiplier; } if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } // Weed levels. if (WeedLevel > 0) { // TODO: Parasitic plants. if (WeedLevel >= Seed.WeedTolerance) { Health -= HydroponicsSpeedMultiplier; } if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } if (Age > Seed.Lifespan) { Health -= _random.Next(3, 5) * HydroponicsSpeedMultiplier; if (DrawWarnings) { _updateSpriteAfterUpdate = true; } } else if (Age < 0) // Revert back to seed packet! { Seed.SpawnSeedPacket(Owner.Transform.Coordinates); RemovePlant(); ForceUpdate = true; Update(); } CheckHealth(); if (Harvest && Seed.HarvestRepeat == HarvestType.SelfHarvest) { AutoHarvest(); } // If enough time has passed since the plant was harvested, we're ready to harvest again! if (!Dead && Seed.ProductPrototypes.Count > 0) { if (Age > Seed.Production) { if ((Age - _lastProduce) > Seed.Production && !Harvest) { Harvest = true; _lastProduce = Age; } } else { if (Harvest) { Harvest = false; _lastProduce = Age; } } } CheckLevelSanity(); if (_updateSpriteAfterUpdate) { UpdateSprite(); } }
public static Vector4 Abs(Vector4 value) { return(new Vector4(MathF.Abs(value.X), MathF.Abs(value.Y), MathF.Abs(value.Z), MathF.Abs(value.W))); }
/// <summary> /// Get the distance between 2 vectors. /// </summary> public static float Distance(Vector from, Vector to) => MathF.Sqrt( MathF.Abs((to.X - from.X) * (to.X - from.X) + (to.Y - from.Y) * (to.Y - from.Y)) );
/// <summary> /// 获取均价 /// </summary> /// <returns></returns> public float GetAvg() { return(MathF.Abs(V_OpenPrice - V_ClosePrice) / 2 + (V_OpenPrice > V_ClosePrice?V_ClosePrice:V_OpenPrice)); }
public bool IsMatch(Dictionary <int, KLineCache> klineDataDic, float btcLSPercent, List <int> MACycleList) { switch (type) { case MatchConditionType.MA: int value = (int)args1; if (!klineDataDic.ContainsKey(value) && value % 1440 == 0) { int merge = value / 1440; KLineCache cache = new KLineCache(); cache.RefreshData(klineDataDic[1440].GetMergeKLine(merge)); klineDataDic[value] = cache; } if (klineDataDic.ContainsKey(value)) { KLineCache kLineCache = klineDataDic[value]; List <float> maList = new List <float>(); List <float> perList = new List <float>(); for (int i = 0; i < paramsList1.Count; i++) { int maIndex = (int)paramsList1[i]; float maValue = 0; if (maIndex == 0) { maValue = kLineCache.V_KLineData[0].V_ClosePrice; } else { if (MACycleList[maIndex - 1] > kLineCache.V_KLineData.Count) { return(false); } maValue = MA.GetMA(MACycleList[maIndex - 1], kLineCache.V_KLineData); } maList.Add(maValue); float perValue = MathF.Abs((kLineCache.V_KLineData[0].V_ClosePrice - maValue) / maValue * 100); perList.Add(perValue); } bool match = true; for (int i = 0; i < maList.Count - 1; i++) { float perValue = MathF.Abs((maList[i] - maList[i + 1]) / maList[i + 1] * 100); if (perValue > 1 && maList[i] < maList[i + 1]) { match = false; break; } } if (match) { for (int i = 0; i < paramsList2.Count; i++) { if (paramsList2[i] < 0) { if (perList[i] < MathF.Abs(paramsList2[i])) { match = false; break; } } else { if (perList[i] > paramsList2[i]) { match = false; break; } } } } return(match); } break; case MatchConditionType.EMA: value = (int)args1; if (klineDataDic.ContainsKey(value)) { KLineCache kLineCache = klineDataDic[value]; List <float> maList = new List <float>(); List <float> perList = new List <float>(); for (int i = 0; i < paramsList1.Count; i++) { int maIndex = (int)paramsList1[i]; float maValue = 0; if (maIndex == 0) { maValue = kLineCache.V_KLineData[0].V_ClosePrice; } else { if (MACycleList[maIndex - 1] > kLineCache.V_KLineData.Count) { return(false); } maValue = EMA.GetEMA(MACycleList[maIndex - 1], kLineCache.V_KLineData); } maList.Add(maValue); float perValue = MathF.Abs((kLineCache.V_KLineData[0].V_ClosePrice - maValue) / maValue * 100); perList.Add(perValue); } bool match = true; for (int i = 0; i < maList.Count - 1; i++) { if (maList[i] < maList[i + 1]) { match = false; break; } } if (match) { for (int i = 0; i < paramsList2.Count; i++) { if (paramsList2[i] < 0) { if (perList[i] < MathF.Abs(paramsList2[i])) { match = false; break; } } else { if (perList[i] > paramsList2[i]) { match = false; break; } } } } return(match); } break; case MatchConditionType.BtcLSPercent: if (args1 < 0) { if (btcLSPercent < MathF.Abs(args1)) { return(false); } return(true); } else { if (btcLSPercent > args1) { return(false); } return(true); } break; case MatchConditionType.PriceList: value = (int)args1; if (klineDataDic.ContainsKey(value)) { KLineCache kLineCache = klineDataDic[value]; bool match = true; int count = (int)paramsList1[0]; if (Math.Abs(count) + 1 > kLineCache.V_KLineData.Count) { return(false); } if (count > 0) { for (int i = 0; i < count; i++) { if (kLineCache.V_KLineData[i].GetAvg() < kLineCache.V_KLineData[i + 1].GetAvg()) { match = false; break; } } } else { for (int i = 0; i < -count; i++) { if (kLineCache.V_KLineData[i].GetAvg() > kLineCache.V_KLineData[i + 1].GetAvg()) { match = false; break; } } } return(match); } break; case MatchConditionType.OldPrice: value = (int)args1; if (klineDataDic.ContainsKey(value)) { KLineCache kLineCache = klineDataDic[value]; bool match = false; int startInedx = (int)paramsList1[0]; int dir = (int)paramsList1[1]; int count = Math.Abs(dir); float curValue = kLineCache.V_KLineData[0].V_ClosePrice; if (startInedx < kLineCache.V_KLineData.Count) { float p1 = kLineCache.V_KLineData[startInedx].GetAvg(); float p2 = kLineCache.V_KLineData[startInedx - count].GetAvg(); float percent = MathF.Abs((p1 - p2) / p2 * 100); if (percent > 2) { if (dir > 0) { if (p1 < p2 && curValue < p1) { match = true; } } else { if (p1 > p2 && curValue > p1) { match = true; } } } } return(match); } break; default: break; } return(false); }
public void method6(Span <SkelBoneState> boneStateOut, float timeChanged, float distanceChanged, float rotationChanged) { // In ToEE, boneIdx is never set to anything other than -1 if (duration > 0) { // Decide what the effective advancement in the animation stream will be float effectiveAdvancement; switch (animation.DriveType) { case SkelAnimDriver.Time: effectiveAdvancement = timeChanged; break; case SkelAnimDriver.Distance: effectiveAdvancement = ownerAnim.scaleInv * distanceChanged; break; case SkelAnimDriver.Rotation: // TODO: Weirdly enough, in the other function it's using the absolute value of it // Does this mean that rotation-based animations will not properly trigger events??? effectiveAdvancement = MathF.Abs(rotationChanged); break; default: throw new AasException($"Unknown animation drive type: {animation.DriveType}"); } // Same logic as in AddTime for events, just different data fields and no event handling currentTime += effectiveAdvancement; if (currentTime > duration) { if (animation.Loopable) { var extraTime = currentTime - duration; currentTime = extraTime; if (currentTime > duration) { if (extraTime - effectiveAdvancement == 0.0f) { currentTime = 0.0f; } else { currentTime = duration; } } } else { currentTime = duration; } } // Propagate the frame index derived from the current time to all streams for (int i = 0; i < streamCount; i++) { var frame = streamFps[i] * currentTime; streams[i].SetFrame(frame); } } if (streamCount != 1 || ownerAnim.variationCount != 1 || weight != 1.0f) { // Get the bone data for each stream Span <SkelBoneState> boneData = stackalloc SkelBoneState[4 * 1024]; // 4 streams with at most 1024 bones each for (int i = 0; i < streamCount; i++) { streams[i].GetBoneState(boneData.Slice(i * 1024, 1024)); } var boneCount = ownerAnim.skeleton.Bones.Count; Trace.Assert(boneCount <= 1024); Span <SkelBoneState> boneDataTemp = stackalloc SkelBoneState[1024]; var boneDataBuf = boneDataTemp; if (weight == 1.0f) { boneDataBuf = boneStateOut; } // Copy over the first stream's bone data boneData.Slice(1024 * streamVariationIndices[0], boneDataBuf.Length).CopyTo(boneDataBuf); // LERP the rest for (var i = 1; i < ownerAnim.variationCount; i++) { if (streamVariationIndices[i] < 4) { var factor = ownerAnim.variations[i].factor; SkelBoneState.Lerp(boneDataBuf, boneDataBuf, boneData.Slice(1024 * streamVariationIndices[i], 1024), boneCount, factor); } } SkelBoneState.Lerp(boneStateOut, boneStateOut, boneDataBuf, boneCount, weight); } else { streams[0].GetBoneState(boneStateOut); } }
internal void Update() { this.AcquireConfigObjects(); Transform transform = this.GameObj.Transform; float scaledRad = this.radius * transform.Scale; Agent[] otherAgents = AgentManager.Instance.FindNeighborAgents(this).ToArray(); this.sampler.Reset(); bool keepSampling = true; Vector2 bestVelocity = Vector2.Zero; float bestScore = float.PositiveInfinity; while (keepSampling) { Vector2 sample = this.sampler.GetCurrentSample(this) * this.characteristics.MaxSpeed; // penalities float toiPenality = 0f; // check against every obstacle foreach (Agent otherAgent in otherAgents) { Transform otherTransform = otherAgent.GameObj.Transform; float curToiPenality = 0f; // calculate helper variables for RVO Vector2 relPos = otherTransform.Pos.Xy - transform.Pos.Xy; // -> calculate side (only sign is of interest) for HRVO Vector2 averageVel = 0.5f * (transform.Vel.Xy + otherTransform.Vel.Xy); float side = Vector2.Dot(relPos.PerpendicularRight, sample - averageVel); float selfFactor = 0f; float otherFactor = 1f; if (side >= 0f) { // this is different from original RVO - we use the ratio of the observed velocities to determine // how much responsibility one agent has float selfSpeed = transform.Vel.Xy.Length; float otherSpeed = otherTransform.Vel.Xy.Length; selfFactor = 0.5f; var selfPlusOtherSpeed = selfSpeed + otherSpeed; if (selfPlusOtherSpeed > float.Epsilon) { selfFactor = otherSpeed / selfPlusOtherSpeed; } otherFactor = 1f - selfFactor; } // check time of impact float curMinToi; float curMaxToi; Vector2 expectedRelVel = sample - (selfFactor * transform.Vel.Xy + otherFactor * otherTransform.Vel.Xy); float otherScaledRad = otherAgent.radius * otherTransform.Scale; if (ToiCircleCircle(relPos, scaledRad + otherScaledRad, expectedRelVel, out curMinToi, out curMaxToi) && 0f < curMaxToi) { if (curMinToi <= 0f) { // we collided - check which way we get here out if (MathF.Abs(curMinToi) < MathF.Abs(curMaxToi)) { // => if minT (which is behind us) is lower then it's a bad idea to keep going because the // other way would bring us out earlier curToiPenality = float.PositiveInfinity; } else { curToiPenality = curMaxToi; } } else { // this is a new minimum toi // => calculate penality curToiPenality = MathF.Max(0f, this.toiHorizon - curMinToi) / this.toiHorizon; } } toiPenality = MathF.Max(toiPenality, curToiPenality); } // ask the characteristics implementation how good this sample is float score = characteristics.CalculateVelocityCost(this, sample, toiPenality); // update sampler and check if we should stop keepSampling = sampler.SetCurrentCost(score); // check if this velocity is better then everything else we've seen so far if (score < bestScore) { bestScore = score; bestVelocity = sample; } #region visual logging of all sampled velocities #if DEBUG if (DebugVisualizationMode != VisualLoggingMode.None && DebugVisualizationMode != VisualLoggingMode.VelocityOnly && DebugVisualizationMode != VisualLoggingMode.AllVelocities) { Vector2 debugPos = sample / this.characteristics.MaxSpeed * DebugVelocityRadius; float debugColorFactor = 0.0f; switch (DebugVisualizationMode) { case VisualLoggingMode.Cost: debugColorFactor = score; break; case VisualLoggingMode.ToiPenalty: debugColorFactor = toiPenality; break; } ColorRgba debugColor = ColorRgba.Lerp(ColorRgba.White, ColorRgba.Black, MathF.Pow(debugColorFactor, 1f / 4f)); VisualDebugLog.DrawCircle(debugPos.X, debugPos.Y, 4f).AnchorAt(this.GameObj).WithColor(debugColor); } #endif #endregion } this.suggestedVel = bestVelocity; #region visual logging of the velocities #if DEBUG if (DebugVisualizationMode == VisualLoggingMode.AllVelocities) { Vector2 selfDebugVelocity = transform.Vel.Xy / Characteristics.MaxSpeed * DebugVelocityRadius; VisualDebugLog.DrawVector(0f, 0f, selfDebugVelocity.X, selfDebugVelocity.Y).AnchorAt(GameObj).WithColor(ColorRgba.DarkGrey); foreach (var otherAgent in otherAgents) { Transform otherTransform = otherAgent.GameObj.Transform; Vector2 debugVelocity = otherTransform.Vel.Xy / otherAgent.Characteristics.MaxSpeed * DebugVelocityRadius; VisualDebugLog.DrawVector(0f, 0f, debugVelocity.X, debugVelocity.Y).AnchorAt(otherAgent.GameObj).WithColor(ColorRgba.DarkGrey); } } if (DebugVisualizationMode != VisualLoggingMode.None) { Vector2 curVelocity = transform.Vel.Xy / Characteristics.MaxSpeed * DebugVelocityRadius; VisualDebugLog.DrawVector(0f, 0f, curVelocity.X, curVelocity.Y).AnchorAt(GameObj).WithColor(ColorRgba.DarkGrey); var debugVelocity = this.suggestedVel / characteristics.MaxSpeed * DebugVelocityRadius; VisualDebugLog.DrawVector(0f, 0f, debugVelocity.X, debugVelocity.Y).AnchorAt(this.GameObj); } #endif #endregion }
public bool filter(CombatUnit unit) { switch (rangeType) { case RangeType.none: return(MathF.Abs(unit.position - pivotPos) <= maxDistance && minDistance <= MathF.Abs(unit.position - pivotPos)); case RangeType.lefthand: return((pivotPos - unit.position) <= maxDistance && minDistance <= (pivotPos - unit.position)); case RangeType.righthand: return(-(pivotPos - unit.position) <= maxDistance && minDistance <= -(pivotPos - unit.position)); } return(MathF.Abs(unit.position - pivotPos) <= maxDistance && minDistance <= MathF.Abs(unit.position - pivotPos)); }
protected internal override void OnCollectDrawcalls(Canvas canvas) { base.OnCollectDrawcalls(canvas); List <RigidBody> visibleColliders = this.QueryVisibleColliders().ToList(); this.RetrieveResources(); RigidBody selectedBody = this.QuerySelectedCollider(); canvas.State.TextFont = Font.GenericMonospace10; canvas.State.TextInvariantScale = true; canvas.State.ZOffset = -1; Font textFont = canvas.State.TextFont.Res; // Draw Shape layer foreach (RigidBody c in visibleColliders) { if (!c.Shapes.Any()) { continue; } float colliderAlpha = c == selectedBody ? 1.0f : (selectedBody != null ? 0.25f : 0.5f); float maxDensity = c.Shapes.Max(s => s.Density); float minDensity = c.Shapes.Min(s => s.Density); float avgDensity = (maxDensity + minDensity) * 0.5f; Vector3 colliderPos = c.GameObj.Transform.Pos; float colliderScale = c.GameObj.Transform.Scale; int index = 0; foreach (ShapeInfo s in c.Shapes) { CircleShapeInfo circle = s as CircleShapeInfo; PolyShapeInfo poly = s as PolyShapeInfo; // EdgeShapeInfo edge = s as EdgeShapeInfo; LoopShapeInfo loop = s as LoopShapeInfo; float shapeAlpha = colliderAlpha * (selectedBody == null || this.View.ActiveState.SelectedObjects.Any(sel => sel.ActualObject == s) ? 1.0f : 0.5f); float densityRelative = MathF.Abs(maxDensity - minDensity) < 0.01f ? 1.0f : s.Density / avgDensity; ColorRgba clr = s.IsSensor ? this.ShapeSensorColor : this.ShapeColor; ColorRgba fontClr = this.FgColor; Vector2 center = Vector2.Zero; if (!c.IsAwake) { clr = clr.ToHsva().WithSaturation(0.0f).ToRgba(); } if (!s.IsValid) { clr = this.ShapeErrorColor; } if (circle != null) { Vector2 circlePos = circle.Position * colliderScale; MathF.TransformCoord(ref circlePos.X, ref circlePos.Y, c.GameObj.Transform.Angle); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha((0.25f + densityRelative * 0.25f) * shapeAlpha))); canvas.FillCircle( colliderPos.X + circlePos.X, colliderPos.Y + circlePos.Y, colliderPos.Z, circle.Radius * colliderScale); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha(shapeAlpha))); canvas.DrawCircle( colliderPos.X + circlePos.X, colliderPos.Y + circlePos.Y, colliderPos.Z, circle.Radius * colliderScale); center = circlePos; } else if (poly != null) { Vector2[] polyVert = poly.Vertices.ToArray(); for (int i = 0; i < polyVert.Length; i++) { center += polyVert[i]; Vector2.Multiply(ref polyVert[i], colliderScale, out polyVert[i]); MathF.TransformCoord(ref polyVert[i].X, ref polyVert[i].Y, c.GameObj.Transform.Angle); } center /= polyVert.Length; Vector2.Multiply(ref center, colliderScale, out center); MathF.TransformCoord(ref center.X, ref center.Y, c.GameObj.Transform.Angle); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha((0.25f + densityRelative * 0.25f) * shapeAlpha))); canvas.FillPolygon(polyVert, colliderPos.X, colliderPos.Y, colliderPos.Z); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha(shapeAlpha))); canvas.DrawPolygon(polyVert, colliderPos.X, colliderPos.Y, colliderPos.Z); } else if (loop != null) { Vector2[] loopVert = loop.Vertices.ToArray(); for (int i = 0; i < loopVert.Length; i++) { center += loopVert[i]; Vector2.Multiply(ref loopVert[i], colliderScale, out loopVert[i]); MathF.TransformCoord(ref loopVert[i].X, ref loopVert[i].Y, c.GameObj.Transform.Angle); } center /= loopVert.Length; Vector2.Multiply(ref center, colliderScale, out center); MathF.TransformCoord(ref center.X, ref center.Y, c.GameObj.Transform.Angle); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, clr.WithAlpha(shapeAlpha))); canvas.DrawPolygon(loopVert, colliderPos.X, colliderPos.Y, colliderPos.Z); } // Draw shape index if (c == selectedBody) { Vector2 textSize = textFont.MeasureText(index.ToString(CultureInfo.InvariantCulture)); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, fontClr.WithAlpha((shapeAlpha + 1.0f) * 0.5f))); canvas.State.TransformHandle = textSize * 0.5f; canvas.DrawText(index.ToString(CultureInfo.InvariantCulture), colliderPos.X + center.X, colliderPos.Y + center.Y, colliderPos.Z); canvas.State.TransformHandle = Vector2.Zero; } index++; } // Draw center of mass if (c.BodyType == BodyType.Dynamic) { Vector2 localMassCenter = c.LocalMassCenter; MathF.TransformCoord(ref localMassCenter.X, ref localMassCenter.Y, c.GameObj.Transform.Angle, c.GameObj.Transform.Scale); canvas.State.SetMaterial(new BatchInfo(DrawTechnique.Alpha, this.MassCenterColor.WithAlpha(colliderAlpha))); canvas.DrawLine( colliderPos.X + localMassCenter.X - 5.0f, colliderPos.Y + localMassCenter.Y, colliderPos.Z, colliderPos.X + localMassCenter.X + 5.0f, colliderPos.Y + localMassCenter.Y, colliderPos.Z); canvas.DrawLine( colliderPos.X + localMassCenter.X, colliderPos.Y + localMassCenter.Y - 5.0f, colliderPos.Z, colliderPos.X + localMassCenter.X, colliderPos.Y + localMassCenter.Y + 5.0f, colliderPos.Z); } } }
public override Color At(Vector4 point) => MathF.Abs((MathF.Floor(point.X) + MathF.Floor(point.Y) + MathF.Floor(point.Z)) % 2) <= Constants.EpsilonLow ? A : B;
protected override void UpdateBase(Color3 gridColor, float alpha, int gridAxisIndex, float sceneUnit) { var cameraService = Game.EditorServices.Get <IEditorGameCameraService>(); if (cameraService == null) { return; } // update the grid color GridMaterial.Passes[0].Parameters.Set(GridColorKey, Color4.PremultiplyAlpha(new Color4(gridColor, alpha))); // Determine the up vector depending on view matrix and projection mode // -> When orthographic, if we are looking along a coordinate axis, place the grid perpendicular to that axis. // -> Place the grid perpendicular to its default axis otherwise. var viewAxisIndex = gridAxisIndex; var upVector = new Vector3(0) { [gridAxisIndex] = 1 }; var viewInvert = Matrix.Invert(cameraService.ViewMatrix); if (cameraService.IsOrthographic) { for (var i = 0; i < 3; i++) { var coordinateAxis = new Vector3 { [i] = 1.0f }; var dotProduct = Vector3.Dot(viewInvert.Forward, coordinateAxis); if (MathF.Abs(dotProduct) > 0.99f) { upVector = coordinateAxis; viewAxisIndex = i; } } } // Check if the inverted View Matrix is valid (since it will be use for mouse picking, check the translation vector only) if (float.IsNaN(viewInvert.TranslationVector.X) || float.IsNaN(viewInvert.TranslationVector.Y) || float.IsNaN(viewInvert.TranslationVector.Z)) { return; } // The position of the grid and the origin in the scene var snappedPosition = Vector3.Zero; var originPosition = Vector3.Zero; // Add a small offset along the Up axis to avoid depth-fight with objects positioned at height=0 snappedPosition[viewAxisIndex] = MathF.Sign(viewInvert[3, viewAxisIndex]) * GridVerticalOffset * sceneUnit; // Move the grid origin in slightly in front the grid to have it in the foreground originPosition[viewAxisIndex] = snappedPosition[viewAxisIndex] + MathF.Sign(viewInvert[3, viewAxisIndex]) * 0.001f * sceneUnit; // Determine the intersection point of the center of the vieport with the grid plane var ray = EditorGameHelper.CalculateRayFromMousePosition(cameraService.Component, new Vector2(0.5f), viewInvert); var plane = new Plane(Vector3.Zero, upVector); var intersection = EditorGameHelper.ProjectOnPlaneWithLimitAngle(ray, plane, MaximumViewAngle); // Detemine the scale of the grid depending of the distance of the camera to the grid plane // For orthographic projections, use a distance close to the one, at which the perspective projection would map to the viewport area. var gridScale = sceneUnit; var distanceToGrid = cameraService.IsOrthographic ? cameraService.Component.OrthographicSize * 1.5f : (viewInvert.TranslationVector - intersection).Length(); if (distanceToGrid < 1.5f * sceneUnit) { gridScale = 0.1f * sceneUnit; } if (distanceToGrid > 40f * sceneUnit) { gridScale = 10f * sceneUnit; } if (distanceToGrid > 400f * sceneUnit) { gridScale = 100f * sceneUnit; } // Snap the grid the closest possible to the intersection point var gridStringLineUnit = gridScale; for (var i = 0; i < 3; i++) { if (viewAxisIndex != i) { snappedPosition[i] += MathF.Round(intersection[i] / gridStringLineUnit) * gridStringLineUnit; } } // Apply positions grid.Transform.Position = snappedPosition; originAxis.TransformValue.Position = originPosition; for (int axis = 0; axis < 3; axis++) { originAxes[axis].TransformValue.Position[axis] = snappedPosition[axis]; } // Apply the scale (Note: scale cannot be applied at root or sub-position is scaled too) grid.Transform.Scale = new Vector3(gridScale); for (int axis = 0; axis < 3; axis++) { originAxes[axis].TransformValue.Scale = new Vector3(gridScale); } // Determine and apply the rotation to the grid and origin axis entities SetPlaneEntityRotation(2, upVector, grid); for (var axis = 0; axis < 3; axis++) { SetPlaneEntityRotation((axis + 2) % 3, upVector, originAxes[axis]); } // Update the color of the origin axes and hide the grid axis for (int axis = 0; axis < 3; axis++) { // Make the axes alpha higher than the grid alpha so they are visible float axesAlpha = alpha * 4; var color = Color4.PremultiplyAlpha(new Color4(GetAxisDefaultColor(axis), axesAlpha)); originAxes[axis].GetChild(0).Get <ModelComponent>().GetMaterial(0).Passes[0].Parameters.Set(GridColorKey, color); originAxes[axis].GetChild(0).Get <ModelComponent>().Enabled = axis != viewAxisIndex; } }
/// <summary> /// Updates host viewport transform and clipping state based on current GPU state. /// </summary> /// <param name="state">Current GPU state</param> private void UpdateViewportTransform(GpuState state) { DepthMode depthMode = state.Get <DepthMode>(MethodOffset.DepthMode); _context.Renderer.Pipeline.SetDepthMode(depthMode); YControl yControl = state.Get <YControl>(MethodOffset.YControl); bool flipY = yControl.HasFlag(YControl.NegateY); Origin origin = yControl.HasFlag(YControl.TriangleRastFlip) ? Origin.LowerLeft : Origin.UpperLeft; _context.Renderer.Pipeline.SetOrigin(origin); // The triangle rast flip flag only affects rasterization, the viewport is not flipped. // Setting the origin mode to upper left on the host, however, not only affects rasterization, // but also flips the viewport. // We negate the effects of flipping the viewport by flipping it again using the viewport swizzle. if (origin == Origin.UpperLeft) { flipY = !flipY; } Span <Viewport> viewports = stackalloc Viewport[Constants.TotalViewports]; for (int index = 0; index < Constants.TotalViewports; index++) { var transform = state.Get <ViewportTransform>(MethodOffset.ViewportTransform, index); var extents = state.Get <ViewportExtents> (MethodOffset.ViewportExtents, index); float x = transform.TranslateX - MathF.Abs(transform.ScaleX); float y = transform.TranslateY - MathF.Abs(transform.ScaleY); float width = MathF.Abs(transform.ScaleX) * 2; float height = MathF.Abs(transform.ScaleY) * 2; float scale = TextureManager.RenderTargetScale; if (scale != 1f) { x *= scale; y *= scale; width *= scale; height *= scale; } RectangleF region = new RectangleF(x, y, width, height); ViewportSwizzle swizzleX = transform.UnpackSwizzleX(); ViewportSwizzle swizzleY = transform.UnpackSwizzleY(); ViewportSwizzle swizzleZ = transform.UnpackSwizzleZ(); ViewportSwizzle swizzleW = transform.UnpackSwizzleW(); if (transform.ScaleX < 0) { swizzleX ^= ViewportSwizzle.NegativeFlag; } if (flipY) { swizzleY ^= ViewportSwizzle.NegativeFlag; } if (transform.ScaleY < 0) { swizzleY ^= ViewportSwizzle.NegativeFlag; } if (transform.ScaleZ < 0) { swizzleZ ^= ViewportSwizzle.NegativeFlag; } viewports[index] = new Viewport( region, swizzleX, swizzleY, swizzleZ, swizzleW, extents.DepthNear, extents.DepthFar); } _context.Renderer.Pipeline.SetViewports(0, viewports); }
internal string GetInfo(MainPage.PolygonUnit polygonUnitValue) { if (CurrentIndex.IsValid()) { var m_path = Paths[CurrentIndex.BlockIndex]; if (polygonUnitValue == PolygonUnit.Symmetry) { if (CurrentIndex.BlockIndex == Paths.Count - 1) { Vector2 start = m_path[0].GetPoint(); Vector2 end = m_path[1].GetPoint(); var v1 = end - start; var a1 = MathF.Atan2(v1.Y, v1.X); string text = string.Format("始点({0:0.00},{1:0.00}) 終点({2:0.00},{3:0.00}) 角度({4:0.0}) ", start.X, start.Y, end.X, end.Y, CmUtils.ToAngle(a1)); return(text); } else { Vector2 start = new Vector2(); Vector2 end = new Vector2(); var item = m_path[CurrentIndex.ItemIndex]; var p = item.GetPoint(CurrentIndex.PartIndex); if (RulerEnabled) { var ruler = Paths[Paths.Count - 1]; start = ruler[0].GetPoint(); end = ruler[1].GetPoint(); } else { CalcReferenceLine(ref start, ref end); } /* * */ var v1 = end - start; var a1 = MathF.Atan2(v1.Y, v1.X); var v2 = p - start; var a2 = MathF.Atan2(v2.Y, v2.X); var l = MathF.Abs(MathF.Sin(a2 - a1) * MathF.Sqrt(MathF.Pow(v2.X, 2) + MathF.Pow(v2.Y, 2))); var l2 = MathF.Cos(a2 - a1) * MathF.Sqrt(MathF.Pow(v2.X, 2) + MathF.Pow(v2.Y, 2)); string text = string.Format("基準から:{1:0.0} 中心線から:{0:0.0} $$ ", l, l2); string info = item.GetInfo(CurrentIndex.PartIndex, true); return(text + info); } } else if (polygonUnitValue == PolygonUnit.RulerOrigin) { if (RulerVisible) { var ruler = Paths[Paths.Count - 1]; var v = ruler[0].GetPoint(); var item = m_path[CurrentIndex.ItemIndex]; string info = item.GetInfo(CurrentIndex.PartIndex, true); string text = string.Format("原点:{0:0.0} {1:0.0}", v.X, v.Y); var p = item.GetPoint(); var ofy = p.Y - v.Y; var ofx = p.X - v.X; float r = MathF.Sqrt(MathF.Pow(ofx, 2) + MathF.Pow(ofy, 2)); var a = MathF.Atan2(ofy, ofx); text += string.Format(" 半径 {0:0.00} 角度 {1:0.00}", r, ToAngle(a)); return(text + info); } } else if (polygonUnitValue != MainPage.PolygonUnit.none) { int unit = (int)polygonUnitValue; var count = m_path.Count - 1; if (IsSameLast(m_path)) { count--; } if (count >= unit * 2 && count % 2 == 0) { var PolygonCenter = CalcCenter(m_path); string text = string.Format("中心:{0:0.0} {1:0.0}", PolygonCenter.X, PolygonCenter.Y); var index = CurrentIndex.ItemIndex;// if (index >= 0) { var item = m_path[index]; var p = item.GetPoint(); var v = PolygonCenter; var ofy = p.Y - v.Y; var ofx = p.X - v.X; float r = MathF.Sqrt(MathF.Pow(ofx, 2) + MathF.Pow(ofy, 2)); var a = MathF.Atan2(ofy, ofx); text += string.Format(" 半径 {0:0.00} 角度 {1:0.00}", r, ToAngle(a)); var partIndex = CurrentIndex.PartIndex; // string info = item.GetInfo(partIndex, true); text += info; } return(text); } } { var index = CurrentIndex.ItemIndex; // var partIndex = CurrentIndex.PartIndex; // if (index >= 0) { var item = m_path[index]; string info = item.GetInfo(partIndex); return(info); } } } return("選択されていません"); }
public static bool AreRoughlyTheSame(float a, float b, float threshold = float.Epsilon) { return(MathF.Abs(a - b) < threshold); }
public static Vector3 Abs(Vector3 value) { return(new Vector3(MathF.Abs(value.X), MathF.Abs(value.Y), MathF.Abs(value.Z))); }
/// <summary> /// Pre calculations for flat microscale terrain /// </summary> public static void Calculate() { Console.WriteLine(); Console.WriteLine("FLOW FIELD COMPUTATION WITHOUT TOPOGRAPHY"); Program.KADVMAX = 1; Program.SubDomainRefPos = new IntPoint(1, 1); int inumm = Program.MetProfileNumb; //set wind-speed components equal to zero Parallel.For(1, Program.NII + 2, Program.pOptions, i => { for (int j = 1; j <= Program.NJJ + 1; j++) { float[] UK_L = Program.UK[i][j]; float[] VK_L = Program.VK[i][j]; float[] WK_L = Program.WK[i][j]; for (int k = 1; k <= Program.NKK; k++) { UK_L[k] = 0; VK_L[k] = 0; WK_L[k] = 0; } } }); //Set initial wind components of the GRAL wind field object obj = new object(); //Parallel.For(1, Program.NII + 1, Program.pOptions, i => Parallel.ForEach(Partitioner.Create(1, Program.NII + 1, Math.Max(4, (int)(Program.NII / Program.pOptions.MaxDegreeOfParallelism))), range => { int KADVMAX1 = 1; for (int i = range.Item1; i < range.Item2; i++) { for (int j = 1; j <= Program.NJJ; j++) { Program.AHK[i][j] = 0; Program.KKART[i][j] = 0; //Pointers (to speed up the computations) float[] UK_L = Program.UK[i][j]; float[] VK_L = Program.VK[i][j]; float[] UKi_L = Program.UK[i + 1][j]; float[] VKj_L = Program.VK[i][j + 1]; double UXint; double UYint; float vertk; float exponent; float dumfac; float ObLength = Program.Ob[1][1]; if (Program.AdaptiveRoughnessMax > 0) { ObLength = Program.OLGral[i][j]; } for (int k = Program.NKK; k >= 1; k--) { vertk = Program.HOKART[k - 1] + Program.DZK[k] * 0.5F; if (vertk > Program.CUTK[i][j]) { //interpolation between observations if (vertk <= Program.MeasurementHeight[1]) { if (ObLength <= 0) { exponent = MathF.Max(0.35F - 0.4F * MathF.Pow(MathF.Abs(ObLength), -0.15F), 0.05F); } else { exponent = 0.56F * MathF.Pow(ObLength, -0.15F); } dumfac = MathF.Pow(vertk / Program.MeasurementHeight[1], exponent); UXint = Program.ObsWindU[1] * dumfac; UYint = Program.ObsWindV[1] * dumfac; } else if (vertk > Program.MeasurementHeight[inumm]) { if (inumm == 1) { if (ObLength <= 0) { exponent = MathF.Max(0.35F - 0.4F * MathF.Pow(MathF.Abs(ObLength), -0.15F), 0.05F); } else { exponent = 0.56F * MathF.Pow(ObLength, -0.15F); } dumfac = MathF.Pow(vertk / Program.MeasurementHeight[inumm], exponent); UXint = Program.ObsWindU[inumm] * dumfac; UYint = Program.ObsWindV[inumm] * dumfac; } else { UXint = Program.ObsWindU[inumm]; UYint = Program.ObsWindV[inumm]; } } else { int ipo = 1; for (int iprof = 1; iprof <= inumm; iprof++) { if (vertk > Program.MeasurementHeight[iprof]) { ipo = iprof + 1; } } UXint = Program.ObsWindU[ipo - 1] + (Program.ObsWindU[ipo] - Program.ObsWindU[ipo - 1]) / (Program.MeasurementHeight[ipo] - Program.MeasurementHeight[ipo - 1]) * (vertk - Program.MeasurementHeight[ipo - 1]); UYint = Program.ObsWindV[ipo - 1] + (Program.ObsWindV[ipo] - Program.ObsWindV[ipo - 1]) / (Program.MeasurementHeight[ipo] - Program.MeasurementHeight[ipo - 1]) * (vertk - Program.MeasurementHeight[ipo - 1]); } //finally get wind speeds outside obstacles UK_L[k] = (float)UXint; VK_L[k] = (float)UYint; if (i > 1) { if (vertk <= Program.CUTK[i - 1][j]) { UK_L[k] = 0; } } if (j > 1) { if (vertk <= Program.CUTK[i][j - 1]) { VK_L[k] = 0; } } Program.UK[Program.NII + 1][j][k] = Program.UK[Program.NII][j][k]; Program.VK[i][Program.NJJ + 1][k] = Program.VK[i][Program.NJJ][k]; } else { //set wind speed zero inside obstacles UK_L[k] = 0; if (i < Program.NII) { UKi_L[k] = 0; } VK_L[k] = 0; if (j < Program.NJJ) { VKj_L[k] = 0; } Program.AHK[i][j] = Math.Max(Program.HOKART[k], Program.AHK[i][j]); Program.BUI_HEIGHT[i][j] = Program.AHK[i][j]; Program.KKART[i][j] = Convert.ToInt16(Math.Max(k, Program.KKART[i][j])); if (Program.CUTK[i][j] > 0) { KADVMAX1 = Math.Max(Program.KKART[i][j], KADVMAX1); } } } } } if (KADVMAX1 > Program.KADVMAX) { lock (obj) { Program.KADVMAX = Math.Max(Program.KADVMAX, KADVMAX1); } } }); obj = null; //maximum z-index up to which the microscale flow field is being computed Program.KADVMAX = Math.Min(Program.NKK, Program.KADVMAX + Program.VertCellsFF); Program.AHMIN = 0; //in case of the diagnostic approach, a boundary layer is established near the obstacle's walls if (Program.FlowFieldLevel <= 1) { Parallel.For((1 + Program.IGEB), (Program.NII - Program.IGEB + 1), Program.pOptions, i => { for (int j = 1 + Program.IGEB; j <= Program.NJJ - Program.IGEB; j++) { double entf = 0; double vertk; double abmind; for (int k = 1; k < Program.NKK; k++) { abmind = 1; vertk = Program.HOKART[k - 1] + Program.DZK[k] * 0.5; //search towards west for obstacles for (int ig = i - Program.IGEB; ig < i; ig++) { entf = 21; if ((vertk <= Program.AHK[ig][j]) && (Program.CUTK[ig][j] > 0) && (k > Program.KKART[i][j])) { entf = Math.Abs((i - ig) * Program.DXK); } } if (entf <= 20) { abmind *= 0.19 * Math.Log((entf + 0.5) * 10); } //search towards east for obstacles for (int ig = i + Program.IGEB; ig >= i + 1; ig--) { entf = 21; if ((vertk <= Program.AHK[ig][j]) && (Program.CUTK[ig][j] > 0) && (k > Program.KKART[i][j])) { entf = Math.Abs((i - ig) * Program.DXK); } } if (entf <= 20) { abmind *= 0.19 * Math.Log((entf + 0.5) * 10); } //search towards south for obstacles for (int jg = j - Program.IGEB; jg < j; jg++) { entf = 21; if ((vertk <= Program.AHK[i][jg]) && (Program.CUTK[i][jg] > 0) && (k > Program.KKART[i][j])) { entf = Math.Abs((j - jg) * Program.DYK); } } if (entf <= 20) { abmind *= 0.19 * Math.Log((entf + 0.5) * 10); } //search towards north for obstacles for (int jg = j + Program.IGEB; jg >= j + 1; jg--) { entf = 21; if ((vertk <= Program.AHK[i][jg]) && (Program.CUTK[i][jg] > 0) && (k > Program.KKART[i][j])) { entf = Math.Abs((j - jg) * Program.DYK); } } if (entf <= 20) { abmind *= 0.19 * Math.Log((entf + 0.5) * 10); } //search towards north/east for obstacles for (int ig = i + Program.IGEB; ig >= i + 1; ig--) { int jg = j + ig - i; entf = 21; if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j])) { entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK)); } } if (entf <= 20) { abmind *= 0.19 * Math.Log((entf + 0.5) * 10); } //search towards south/west for obstacles for (int ig = i - Program.IGEB; ig < i; ig++) { int jg = j + ig - i; entf = 21; if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j])) { entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK)); } } if (entf <= 20) { abmind *= 0.19 * Math.Log((entf + 0.5) * 10); } //search towards south/east for obstacles for (int ig = i + Program.IGEB; ig >= i + 1; ig--) { int jg = j - ig + i; entf = 21; if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j])) { entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK)); } } if (entf <= 20) { abmind *= 0.19 * Math.Log((entf + 0.5) * 10); } //search towards north/west for obstacles for (int ig = i - Program.IGEB; ig < i; ig++) { int jg = j - ig + i; entf = 21; if ((vertk <= Program.AHK[ig][jg]) && (Program.CUTK[ig][jg] > 0) && (k > Program.KKART[i][j])) { entf = Math.Sqrt(Program.Pow2((i - ig) * Program.DXK) + Program.Pow2((j - jg) * Program.DYK)); } } if (entf <= 20) { abmind *= 0.19 * Math.Log((entf + 0.5) * 10); } Program.UK[i][j][k] *= (float)abmind; Program.VK[i][j][k] *= (float)abmind; } } }); } //computing flow field either with diagnostic or prognostic approach if (Program.FlowFieldLevel > 0) { //diagnostic approach if (Program.FlowFieldLevel == 1) { Console.WriteLine("DIAGNOSTIC WIND FIELD AROUND OBSTACLES"); DiagnosticFlowfield.Calculate(); } //prognostic approach if (Program.FlowFieldLevel == 2) { //read vegetation only one times if (Program.VEG[0][0][0] < 0) { ProgramReaders Readclass = new ProgramReaders(); Readclass.ReadVegetationDomain(null); Readclass.ReadVegetation(); } Console.WriteLine("PROGNOSTIC WIND FIELD AROUND OBSTACLES"); PrognosticFlowfield.Calculate(); } //Final mass conservation using poisson equation for pressure after advection has been computed with level 2 if (Program.FlowFieldLevel == 2) { DiagnosticFlowfield.Calculate(); } } //in diagnostic mode mass-conservation is finally achieved by adjusting the vertical velocity in each cell if (Program.FlowFieldLevel < 2) { Parallel.For(2, Program.NII, Program.pOptions, i => { for (int j = 2; j < Program.NJJ; j++) { //Pointers (to speed up the computations) float[] UK_L = Program.UK[i][j]; float[] UKi_L = Program.UK[i + 1][j]; float[] VK_L = Program.VK[i][j]; float[] VKj_L = Program.VK[i][j + 1]; float[] WK_L = Program.WK[i][j]; double fwo1 = 0; double fwo2 = 0; double fsn1 = 0; double fsn2 = 0; double fbt1 = 0; int KKART = Program.KKART[i][j]; for (int k = 1; k < Program.NKK; k++) { if (k > KKART) { if (k <= Program.KKART[i - 1][j]) { fwo1 = 0; } else { fwo1 = Program.DZK[k] * Program.DYK * UK_L[k]; } if (k <= Program.KKART[i + 1][j]) { fwo2 = 0; } else { fwo2 = Program.DZK[k] * Program.DYK * UKi_L[k]; } if (k <= Program.KKART[i][j - 1]) { fsn1 = 0; } else { fsn1 = Program.DZK[k] * Program.DXK * VK_L[k]; } if (k <= Program.KKART[i][j + 1]) { fsn2 = 0; } else { fsn2 = Program.DZK[k] * Program.DXK * VKj_L[k]; } if ((k <= KKART + 1) || (k == 1)) { fbt1 = 0; } else { fbt1 = Program.DXK * Program.DYK * WK_L[k]; } WK_L[k + 1] = (float)((fwo1 - fwo2 + fsn1 - fsn2 + fbt1) / (Program.DXK * Program.DYK)); } } } }); } }
protected override unsafe int ProcessBlock(float *input, float *output, int count, int outputCount, out int inputIndex) { inputIndex = 0; int outputIndex = 0; int consumable = count - 8; //Loop through until we run out of space for something while (outputIndex < outputCount && inputIndex < consumable) { //Produce output output[outputIndex] = Interpolate(&input[inputIndex], mu); float mm_val = Binaryify(lastSample) * output[outputIndex] - Binaryify(output[outputIndex]) * lastSample; lastSample = output[outputIndex]; //Calculate error omega = omega + gainOmega * mm_val; omega = omegaMid + (0.5f * (MathF.Abs((omega - omegaMid) + omegaLim) - MathF.Abs((omega - omegaMid) - omegaLim))); mu = mu + omega + gainMu * mm_val; //Offset by error inputIndex += (int)MathF.Floor(mu); mu = mu - MathF.Floor(mu); outputIndex++; } return(outputIndex); }
private static (Size, Rectangle) CalculatePadRectangle( Size source, ResizeOptions options, int width, int height) { if (width <= 0 || height <= 0) { return(new Size(source.Width, source.Height), new Rectangle(0, 0, source.Width, source.Height)); } float ratio; int sourceWidth = source.Width; int sourceHeight = source.Height; int destinationX = 0; int destinationY = 0; int destinationWidth = width; int destinationHeight = height; // Fractional variants for preserving aspect ratio. float percentHeight = MathF.Abs(height / (float)sourceHeight); float percentWidth = MathF.Abs(width / (float)sourceWidth); if (percentHeight < percentWidth) { ratio = percentHeight; destinationWidth = (int)MathF.Round(sourceWidth * percentHeight); switch (options.Position) { case AnchorPositionMode.Left: case AnchorPositionMode.TopLeft: case AnchorPositionMode.BottomLeft: destinationX = 0; break; case AnchorPositionMode.Right: case AnchorPositionMode.TopRight: case AnchorPositionMode.BottomRight: destinationX = (int)MathF.Round(width - (sourceWidth * ratio)); break; default: destinationX = (int)MathF.Round((width - (sourceWidth * ratio)) / 2F); break; } } else { ratio = percentWidth; destinationHeight = (int)MathF.Round(sourceHeight * percentWidth); switch (options.Position) { case AnchorPositionMode.Top: case AnchorPositionMode.TopLeft: case AnchorPositionMode.TopRight: destinationY = 0; break; case AnchorPositionMode.Bottom: case AnchorPositionMode.BottomLeft: case AnchorPositionMode.BottomRight: destinationY = (int)MathF.Round(height - (sourceHeight * ratio)); break; default: destinationY = (int)MathF.Round((height - (sourceHeight * ratio)) / 2F); break; } } return(new Size(width, height), new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight)); }
/// <inheritdoc/> protected override void OnApply(ImageBase <TPixel> source, Rectangle sourceRectangle) { int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int radius = this.BrushSize >> 1; int levels = this.Levels; // Align start/end positions. int minX = Math.Max(0, startX); int maxX = Math.Min(source.Width, endX); int minY = Math.Max(0, startY); int maxY = Math.Min(source.Height, endY); // Reset offset if necessary. if (minX > 0) { startX = 0; } using (var targetPixels = new PixelAccessor <TPixel>(source.Width, source.Height)) { source.CopyTo(targetPixels); Parallel.For( minY, maxY, this.ParallelOptions, y => { Span <TPixel> sourceRow = source.GetRowSpan(y); Span <TPixel> targetRow = targetPixels.GetRowSpan(y); for (int x = startX; x < endX; x++) { int maxIntensity = 0; int maxIndex = 0; int[] intensityBin = new int[levels]; float[] redBin = new float[levels]; float[] blueBin = new float[levels]; float[] greenBin = new float[levels]; for (int fy = 0; fy <= radius; fy++) { int fyr = fy - radius; int offsetY = y + fyr; offsetY = offsetY.Clamp(0, maxY); Span <TPixel> sourceOffsetRow = source.GetRowSpan(offsetY); for (int fx = 0; fx <= radius; fx++) { int fxr = fx - radius; int offsetX = x + fxr; offsetX = offsetX.Clamp(0, maxX); var vector = sourceOffsetRow[offsetX].ToVector4(); float sourceRed = vector.X; float sourceBlue = vector.Z; float sourceGreen = vector.Y; int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); intensityBin[currentIntensity] += 1; blueBin[currentIntensity] += sourceBlue; greenBin[currentIntensity] += sourceGreen; redBin[currentIntensity] += sourceRed; if (intensityBin[currentIntensity] > maxIntensity) { maxIntensity = intensityBin[currentIntensity]; maxIndex = currentIntensity; } } float red = MathF.Abs(redBin[maxIndex] / maxIntensity); float green = MathF.Abs(greenBin[maxIndex] / maxIntensity); float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); ref TPixel pixel = ref targetRow[x]; pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); } } }); source.SwapPixelsBuffers(targetPixels); } }
/// <inheritdoc/> protected override void BeforeApply(ImageBase <TPixel> source, Rectangle sourceRectangle) { if (MathF.Abs(this.Angle) < Constants.Epsilon || MathF.Abs(this.Angle - 90) < Constants.Epsilon || MathF.Abs(this.Angle - 180) < Constants.Epsilon || MathF.Abs(this.Angle - 270) < Constants.Epsilon) { return; } this.processMatrix = Matrix3x2Extensions.CreateRotation(-this.Angle, new Point(0, 0)); if (this.Expand) { this.CreateNewCanvas(sourceRectangle, this.processMatrix); } }
private void DrawLayer(IDrawDevice device, ref TileMapLayer layer, int cacheIndex) { if (!layer.Visible) { return; } Vector2 viewSize = device.TargetSize; Vector3 viewCenter = device.RefCoord; Point2 tileCount = new Point2(layer.LayoutWidth, layer.Layout.Length / layer.LayoutWidth); Vector2 tileSize = new Vector2(tileset.TileSize, tileset.TileSize); // Update offsets for moving layers if (MathF.Abs(layer.AutoSpeedX) > 0) { layer.OffsetX += layer.AutoSpeedX * Time.TimeMult; if (layer.RepeatX) { if (layer.AutoSpeedX > 0) { while (layer.OffsetX > (tileCount.X * 32)) { layer.OffsetX -= (tileCount.X * 32); } } else { while (layer.OffsetX < 0) { layer.OffsetX += (tileCount.X * 32); } } } } if (MathF.Abs(layer.AutoSpeedY) > 0) { layer.OffsetY += layer.AutoSpeedY * Time.TimeMult; if (layer.RepeatY) { if (layer.AutoSpeedY > 0) { while (layer.OffsetY > (tileCount.Y * 32)) { layer.OffsetY -= (tileCount.Y * 32); } } else { while (layer.OffsetY < 0) { layer.OffsetY += (tileCount.Y * 32); } } } } // Get current layer offsets and speeds float loX = layer.OffsetX; float loY = layer.OffsetY - (layer.UseInherentOffset ? (viewSize.Y - 200) / 2 : 0); // Find out coordinates for a tile from outside the boundaries from topleft corner of the screen float x1 = viewCenter.X - 70 - (viewSize.X * 0.5f); float y1 = viewCenter.Y - 70 - (viewSize.Y * 0.5f); if (layer.BackgroundStyle != BackgroundStyle.Plain && tileCount.Y == 8 && tileCount.X == 8) { const float PerspectiveSpeedX = 0.4f; const float PerspectiveSpeedY = 0.16f; RenderTexturedBackground(device, ref layer, cacheIndex, (x1 * PerspectiveSpeedX + loX), (y1 * PerspectiveSpeedY + loY)); } else { // Figure out the floating point offset from the calculated coordinates and the actual tile // corner coordinates float xt = TranslateCoordinate(x1, layer.SpeedX, loX, false, viewSize.Y, viewSize.X); float yt = TranslateCoordinate(y1, layer.SpeedY, loY, true, viewSize.Y, viewSize.X); float remX = xt % 32f; float remY = yt % 32f; // Calculate the index (on the layer map) of the first tile that needs to be drawn to the // position determined earlier int tileX, tileY, tileAbsX, tileAbsY; // Get the actual tile coords on the layer layout if (xt > 0) { tileAbsX = (int)Math.Floor(xt / 32f); tileX = tileAbsX % tileCount.X; } else { tileAbsX = (int)Math.Ceiling(xt / 32f); tileX = tileAbsX % tileCount.X; while (tileX < 0) { tileX += tileCount.X; } } if (yt > 0) { tileAbsY = (int)Math.Floor(yt / 32f); tileY = tileAbsY % tileCount.Y; } else { tileAbsY = (int)Math.Ceiling(yt / 32f); tileY = tileAbsY % tileCount.Y; while (tileY < 0) { tileY += tileCount.Y; } } // update x1 and y1 with the remainder so that we start at the tile boundary // minus 1 because indices are updated in the beginning of the loops x1 -= remX - 32f; y1 -= remY - 32f; // Save the tile Y at the left border so that we can roll back to it at the start of // every row iteration int tileYs = tileY; // Calculate the last coordinates we want to draw to float x3 = x1 + 100 + viewSize.X; float y3 = y1 + 100 + viewSize.Y; Material material = null; Texture texture = null; ColorRgba mainColor = ColorRgba.White; // Reserve the required space for vertex data in our locally cached buffer VertexC1P3T2[] vertexData; int neededVertices = (int)((((x3 - x1) / 32) + 1) * (((y3 - y1) / 32) + 1) * 4); if (cachedVertices[cacheIndex] == null || cachedVertices[cacheIndex].Length < neededVertices) { cachedVertices[cacheIndex] = vertexData = new VertexC1P3T2[neededVertices]; } else { vertexData = cachedVertices[cacheIndex]; } int vertexBaseIndex = 0; int tile_xo = -1; for (float x2 = x1; x2 < x3; x2 += 32) { tileX = (tileX + 1) % tileCount.X; tile_xo++; if (!layer.RepeatX) { // If the current tile isn't in the first iteration of the layer horizontally, don't draw this column if (tileAbsX + tile_xo + 1 < 0 || tileAbsX + tile_xo + 1 >= tileCount.X) { continue; } } tileY = tileYs; int tile_yo = -1; for (float y2 = y1; y2 < y3; y2 += 32) { tileY = (tileY + 1) % tileCount.Y; tile_yo++; LayerTile tile = layer.Layout[tileX + tileY * layer.LayoutWidth]; if (!layer.RepeatY) { // If the current tile isn't in the first iteration of the layer vertically, don't draw it if (tileAbsY + tile_yo + 1 < 0 || tileAbsY + tile_yo + 1 >= tileCount.Y) { continue; } } Point2 offset; bool isFlippedX, isFlippedY; if (tile.IsAnimated) { if (tile.TileID < animatedTiles.Count) { offset = animatedTiles[tile.TileID].CurrentTile.MaterialOffset; isFlippedX = (animatedTiles[tile.TileID].CurrentTile.IsFlippedX != tile.IsFlippedX); isFlippedY = (animatedTiles[tile.TileID].CurrentTile.IsFlippedY != tile.IsFlippedY); //mainColor.A = tile.MaterialAlpha; mainColor.A = animatedTiles[tile.TileID].CurrentTile.MaterialAlpha; } else { continue; } } else { offset = tile.MaterialOffset; isFlippedX = tile.IsFlippedX; isFlippedY = tile.IsFlippedY; mainColor.A = tile.MaterialAlpha; } if (material != tile.Material) { // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, vertexData, 0, vertexBaseIndex); vertexBaseIndex = 0; material = tile.Material.Res; texture = material.MainTexture.Res; } Rect uvRect = new Rect( offset.X * texture.UVRatio.X / texture.ContentWidth, offset.Y * texture.UVRatio.Y / texture.ContentHeight, tileset.TileSize * texture.UVRatio.X / texture.ContentWidth, tileset.TileSize * texture.UVRatio.Y / texture.ContentHeight ); // ToDo: Flip normal map somehow if (isFlippedX) { uvRect.X += uvRect.W; uvRect.W *= -1; } if (isFlippedY) { uvRect.Y += uvRect.H; uvRect.H *= -1; } Vector3 renderPos = new Vector3(x2, y2, layer.Depth); float scale = 1.0f; device.PreprocessCoords(ref renderPos, ref scale); renderPos.X = MathF.Round(renderPos.X); renderPos.Y = MathF.Round(renderPos.Y); if (MathF.RoundToInt(device.TargetSize.X) != (MathF.RoundToInt(device.TargetSize.X) / 2) * 2) { renderPos.X += 0.5f; } if (MathF.RoundToInt(device.TargetSize.Y) != (MathF.RoundToInt(device.TargetSize.Y) / 2) * 2) { renderPos.Y += 0.5f; } vertexData[vertexBaseIndex + 0].Pos.X = renderPos.X; vertexData[vertexBaseIndex + 0].Pos.Y = renderPos.Y; vertexData[vertexBaseIndex + 0].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 0].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 0].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 0].Color = mainColor; vertexData[vertexBaseIndex + 1].Pos.X = renderPos.X; vertexData[vertexBaseIndex + 1].Pos.Y = renderPos.Y + tileSize.Y; vertexData[vertexBaseIndex + 1].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 1].TexCoord.X = uvRect.X; vertexData[vertexBaseIndex + 1].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[vertexBaseIndex + 1].Color = mainColor; vertexData[vertexBaseIndex + 2].Pos.X = renderPos.X + tileSize.X; vertexData[vertexBaseIndex + 2].Pos.Y = renderPos.Y + tileSize.Y; vertexData[vertexBaseIndex + 2].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 2].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 2].TexCoord.Y = uvRect.Y + uvRect.H; vertexData[vertexBaseIndex + 2].Color = mainColor; vertexData[vertexBaseIndex + 3].Pos.X = renderPos.X + tileSize.X; vertexData[vertexBaseIndex + 3].Pos.Y = renderPos.Y; vertexData[vertexBaseIndex + 3].Pos.Z = renderPos.Z; vertexData[vertexBaseIndex + 3].TexCoord.X = uvRect.X + uvRect.W; vertexData[vertexBaseIndex + 3].TexCoord.Y = uvRect.Y; vertexData[vertexBaseIndex + 3].Color = mainColor; vertexBaseIndex += 4; } } // Submit all the vertices as one draw batch device.AddVertices( material, VertexMode.Quads, vertexData, 0, vertexBaseIndex); } }