void UpdateTransform() { // set the transform mat = Matrix3x2.Identity; mat *= Matrix3x2.CreateTranslation(-rect.Width * 0.5f, -rect.Height * 0.5f); mat *= Matrix3x2.CreateScale(this.scale, this.scale); mat *= Matrix3x2.CreateRotation((float)(Math.PI * this.angle / 180f)); mat *= Matrix3x2.CreateTranslation(pos.X, pos.Y); // get the inversed matrix Matrix3x2.Invert(mat, out matInv); }
public void Matrix3x2InvertScaleTest() { Matrix3x2 mtx = Matrix3x2.CreateScale(23, -42); Matrix3x2 actual; Assert.IsTrue(Matrix3x2.Invert(mtx, out actual)); Matrix3x2 i = mtx * actual; Assert.IsTrue(MathHelper.Equal(i, Matrix3x2.Identity)); }
public void Matrix3x2InvertRotationTest() { Matrix3x2 mtx = Matrix3x2.CreateRotation(2); Matrix3x2 actual; Assert.True(Matrix3x2.Invert(mtx, out actual)); Matrix3x2 i = mtx * actual; Assert.True(MathHelper.Equal(i, Matrix3x2.Identity)); }
public void Draw(DrawArgs drawArgs) { _prerenderProvider.CreatePrerenders(drawArgs, _map.Size); // apply view matrix drawArgs.PushScale(_zoom); drawArgs.PushTranslation(_pan); // apply level of detail var drawLod = _zoom > 0.5 ? DrawLevelOfDetail.Normal : DrawLevelOfDetail.Low; drawArgs.LevelOfDetail = drawLod; // calculate viewport transform, used for zoom/pan Matrix3x2.Invert(drawArgs.CurrentTransform, out _mapTransform); // calculate visible field coords var bottomLeftFieldCoords = TranslateToFieldCoords(_bottomLeftViewLimit); var blx = bottomLeftFieldCoords.X; var bly = bottomLeftFieldCoords.Y; var topRightFieldCoords = TranslateToFieldCoords(_topRightViewLimit); var urx = topRightFieldCoords.X; var ury = topRightFieldCoords.Y; // have agents draw themselves layer by layer foreach (var drawLayer in DrawLayers) { drawArgs.Layer = drawLayer; var prerender = _prerenderProvider.GetPrerender(drawLod, drawLayer); if (prerender != null) { drawArgs.Ds.DrawImage(prerender, -_tileRadius, -2.0f * _tileRadiusH); } else { // find indicators which are currently on screen var culledIndicators = _indicatorRegistry .GetIndicators(drawLod, drawLayer) .Where(tm => blx <= tm.Position.X && tm.Position.X <= urx && bly <= tm.Position.Y && tm.Position.Y <= ury); foreach (var indicator in culledIndicators) { indicator.Draw(drawArgs); } } } // restore view matrix drawArgs.Pop(); drawArgs.Pop(); }
public Vector2 InvertTransformPoint(Matrix3x2 matrix, Vector2 point) { if (Matrix3x2.Invert(matrix, out Matrix3x2 inverted)) { return(new Vector2( x: point.X *inverted.M11 + point.Y *inverted.M21 + inverted.M31, y: point.X * inverted.M12 + point.Y * inverted.M22 + inverted.M32 )); } return(point); }
/// <summary> /// Pushes a matrix transformation. /// </summary> /// <param name="matrix">The matrix</param> /// <returns>A disposable used to undo the transformation.</returns> public IDisposable PushTransform(Matrix matrix) { Matrix3x2 m3x2 = matrix.ToDirect2D(); Matrix3x2 transform = this.renderTarget.Transform * m3x2; this.renderTarget.Transform = transform; return(Disposable.Create(() => { m3x2.Invert(); this.renderTarget.Transform = transform * m3x2; })); }
private void DrawDiagnostics(DeviceContext renderTarget) { renderTarget.Transform = Matrix3x2.Identity; Matrix3x2 wt = GlobalTransform; wt.Invert(); var worldPos = Matrix3x2.TransformPoint(wt, MouseClientPosition); renderTarget.DrawText( $"FPS: {RenderTimer.FramesPerSecond:0}\r\nFrameTime: {RenderTimer.DurationSinceLastFrame}\r\n({worldPos.X:0}, {worldPos.Y:0})", XResource.TextFormats[11], new RectangleF(0, 0, 100, 30), XResource.GetColor(Color.White)); }
/// <summary> /// Gets the centered transform matrix based upon the source and destination rectangles /// </summary> /// <param name="sourceRectangle">The source image bounds.</param> /// <param name="destinationRectangle">The destination image bounds.</param> /// <param name="matrix">The transformation matrix.</param> /// <returns>The <see cref="Matrix3x2"/></returns> public static Matrix3x2 GetCenteredTransformMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle, Matrix3x2 matrix) { // We invert the matrix to handle the transformation from screen to world space. // This ensures scaling matrices are correct. Matrix3x2.Invert(matrix, out Matrix3x2 inverted); var translationToTargetCenter = Matrix3x2.CreateTranslation(-destinationRectangle.Width * .5F, -destinationRectangle.Height * .5F); var translateToSourceCenter = Matrix3x2.CreateTranslation(sourceRectangle.Width * .5F, sourceRectangle.Height * .5F); Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); // Translate back to world to pass to the Transform method. return(centered); }
public void Matrix3x2InvertAffineTest() { Matrix3x2 mtx = Matrix3x2.CreateRotation(2) * Matrix3x2.CreateScale(23, -42) * Matrix3x2.CreateTranslation(17, 53); Matrix3x2 actual; Assert.True(Matrix3x2.Invert(mtx, out actual)); Matrix3x2 i = mtx * actual; Assert.True(MathHelper.Equal(i, Matrix3x2.Identity)); }
/// <summary> /// Gets the centered transform matrix based upon the source and destination rectangles. /// </summary> /// <param name="sourceRectangle">The source image bounds.</param> /// <param name="matrix">The transformation matrix.</param> /// <returns>The <see cref="Matrix3x2"/></returns> public static Matrix3x2 CreateCenteredTransformMatrix(Rectangle sourceRectangle, Matrix3x2 matrix) { Rectangle destinationRectangle = GetTransformedBoundingRectangle(sourceRectangle, matrix); // We invert the matrix to handle the transformation from screen to world space. // This ensures scaling matrices are correct. Matrix3x2.Invert(matrix, out Matrix3x2 inverted); var translationToTargetCenter = Matrix3x2.CreateTranslation(new Vector2(-destinationRectangle.Width, -destinationRectangle.Height) * .5F); var translateToSourceCenter = Matrix3x2.CreateTranslation(new Vector2(sourceRectangle.Width, sourceRectangle.Height) * .5F); // Translate back to world space. Matrix3x2.Invert(translationToTargetCenter * inverted * translateToSourceCenter, out Matrix3x2 centered); return(centered); }
// Toggles the color of cells when they are clicked on. private void ProcessPointerInput(PointerRoutedEventArgs e) { if (!isPointerDown) { return; } // Invert the display transform, to convert pointer positions into simulation rendertarget space. Matrix3x2 transform; Matrix3x2.Invert(Utils.GetDisplayTransform(canvas.Size, canvas, simulationW, simulationH), out transform); foreach (var point in e.GetIntermediatePoints(canvas)) { if (!point.IsInContact) { continue; } var pos = Vector2.Transform(point.Position.ToVector2(), transform); var x = canvas.ConvertDipsToPixels(pos.X); var y = canvas.ConvertDipsToPixels(pos.Y); // If the point is within the bounds of the rendertarget, and not the same as the last point... if (x >= 0 && y >= 0 && x < simulationW && y < simulationH && ((x != lastPointerX || y != lastPointerY))) { // Read the current color. var cellColor = currentSurface.GetPixelColors(x, y, 1, 1); // Toggle the value. cellColor[0] = cellColor[0].R > 0 ? Colors.Black : Colors.White; // Set the new color. currentSurface.SetPixelColors(cellColor, x, y, 1, 1); lastPointerX = x; lastPointerY = y; } } }
public void OnEraseSelectFinished(object sender, bool blendCurrentStroke) { List <List <Vector2> > convexHulls = new List <List <Vector2> >(VectorInkBuilder.ConvexHullChainProducer.AllData); if (!TransformationMatrix.IsIdentity) { bool res = Matrix3x2.Invert(TransformationMatrix, out Matrix3x2 viewToModelTransformationMatrix); if (!res) { throw new InvalidOperationException("Transform matrix could not be inverted."); } TransformUtils.TransformPolysXY(convexHulls, viewToModelTransformationMatrix); } mSpatialModel.Erase(convexHulls, mSelectTool.ManipulationMode); }
/// <summary> /// Constructor, creates grid representation and transformations. /// </summary> /// <param name="mapResolution">Map resolution in meters per pixel</param> /// <param name="size">Map size in pixels</param> /// <param name="offset">Offset if meters</param> public GridMap(float mapResolution, Point size, Vector2 offset) { Properties = new MapProperties(mapResolution, size, offset); // Construct map array mapArray = new LogOddsCell[Dimensions.X * Dimensions.Y]; for (int i = 0; i < mapArray.Length; ++i) { mapArray[i].Reset(); } // Construct transformation matrix // TODO Not quite sure if offset is needed mapTworld = Matrix3x2.CreateScale(Properties.ScaleToMap) * Matrix3x2.CreateTranslation(Properties.Offset.X, Properties.Offset.Y); if (!Matrix3x2.Invert(mapTworld, out worldTmap)) { throw new Exception("Map to world matrix is not invertible"); } }
/// <summary> /// Gets the individual pixel coordinates of a collision between two sprites. /// </summary> /// <param name="sprite1">The first sprite.</param> /// <param name="subImage1">The subimage of the first sprite.</param> /// <param name="modelWorldTransform1">The transformation matrix of the first sprite.</param> /// <param name="sprite2">The second sprite.</param> /// <param name="subImage2">The subimage of the second sprite.</param> /// <param name="modelWorldTransform2">The transformation matrix of the second sprite.</param> /// <returns>An enumerable of (x, y) tuple values representing the pixels in the collision.</returns> public IEnumerable <(int x, int y)> GetSpriteCollisions(GameSprite sprite1, int subImage1, Matrix3x2 modelWorldTransform1, GameSprite sprite2, int subImage2, Matrix3x2 modelWorldTransform2) { // First, transform the bounding boxes to account for sprite origin, rotations, scaling, and position. var bb1 = GetSpriteTransformedBoundingBox(sprite1, modelWorldTransform1); var bb2 = GetSpriteTransformedBoundingBox(sprite2, modelWorldTransform2); // Invert the transformation matrixes so we can map world coordinates into sprite coordinates. Matrix3x2.Invert(modelWorldTransform1, out var spriteLocalTransform1); Matrix3x2.Invert(modelWorldTransform2, out var spriteLocalTransform2); // Get the intersection of both bounding boxes. var bbIntersection = bb1.Intersection(ref bb2); // If the bounding boxes don't overlap, there is no collision. if (!bbIntersection.IsValid) { yield break; } // Get the collision mask for each sprite. var mask1 = sprite1.SeparateCollisionMasks ? sprite1.CollisionMasks[subImage1] : sprite1.CollisionMasks[0]; var mask2 = sprite2.SeparateCollisionMasks ? sprite2.CollisionMasks[subImage2] : sprite2.CollisionMasks[0]; // Look at each pixel in the bounding box intersection. for (var x = bbIntersection.Left; x <= bbIntersection.Right; x++) { for (var y = bbIntersection.Top; y <= bbIntersection.Bottom; y++) { // Transform the pixel coordinate to sprite coordinates for both sprites // using the inverted world matrix. var localV1 = Vector2.Transform(new Vector2(x, y), spriteLocalTransform1); var localV2 = Vector2.Transform(new Vector2(x, y), spriteLocalTransform2); // Check if the respective sprite coordinates overlap solid pixels in both sprites. if (mask1.HitTest((int)localV1.X, (int)localV1.Y) && mask2.HitTest((int)localV2.X, (int)localV2.Y)) { yield return(x, y); } } } }
// Toggles the color of cells when they are clicked on. private void ProcessPointerInput(PointerRoutedEventArgs e) { if (!isPointerDown) { return; } // Invert the display transform, to convert pointer positions into simulation rendertarget space. Matrix3x2 transform; Matrix3x2.Invert(GetDisplayTransform(canvas), out transform); foreach (var point in e.GetIntermediatePoints(canvas)) { if (!point.IsInContact) { continue; } var pos = Vector2.Transform(point.Position.ToVector2(), transform); var x = canvas.ConvertDipsToPixels(pos.X, CanvasDpiRounding.Floor); var y = canvas.ConvertDipsToPixels(pos.Y, CanvasDpiRounding.Floor); // If the point is within the bounds of the rendertarget, and not the same as the last point... if (x >= 0 && y >= 0 && x < simulationW && y < simulationH && ((x != lastPointerX || y != lastPointerY))) { // We avoid manipulating GPU resources from inside an input event handler // (since we'd need to handle device lost and possible concurrent running with CreateResources). // Instead, we collect up a list of points and process them from the Draw handler. hitPoints.Add(new IntPoint(x, y)); lastPointerX = x; lastPointerY = y; } } canvas.Invalidate(); }
/// <inheritdoc /> public Point GetPosition(object?relativeTo) { var rawWpfPosition = _wpfArgs.GetPosition(WpfHost.Current); var rawPosition = new Point(rawWpfPosition.X, rawWpfPosition.Y); if (relativeTo is null) { return(rawPosition); } if (relativeTo is UIElement elt) { var eltToRoot = UIElement.GetTransform(elt, null); Matrix3x2.Invert(eltToRoot, out var rootToElt); return(rootToElt.Transform(rawPosition)); } throw new InvalidOperationException("The relative to must be a UIElement."); }
public override void OnReleased(UIElement uiElement, PointerRoutedEventArgs args) { if (mIsTranslating) { Matrix3x2 translation = Matrix3x2.Identity; var pt = args.GetCurrentPoint(uiElement).Position; if (!mStrokeHandler.TransformationMatrix.IsIdentity) { bool res = Matrix3x2.Invert(mStrokeHandler.TransformationMatrix, out Matrix3x2 modelTransformationMatrix); if (!res) { throw new InvalidOperationException("Transform matrix could not be inverted."); } Vector2 currentPointPos = new Vector2((float)pt.X, (float)pt.Y); Vector2 startPos = new Vector2((float)mStartPosition.X, (float)mStartPosition.Y); Vector2 modelCurrentPointPos = Vector2.Transform(currentPointPos, modelTransformationMatrix); Vector2 modelStartPos = Vector2.Transform(startPos, modelTransformationMatrix); double dX = modelCurrentPointPos.X - modelStartPos.X; double dY = modelCurrentPointPos.Y - modelStartPos.Y; translation = Matrix3x2.CreateTranslation((float)dX, (float)dY); } else { double dX = pt.X - mStartPosition.X; double dY = pt.Y - mStartPosition.Y; translation = Matrix3x2.CreateTranslation((float)dX, (float)dY); } TranslateFinished?.Invoke(this, translation); } else { base.OnReleased(uiElement, args); } mIsTranslating = false; }
public void Matrix3x2DeterminantTest1() { Matrix3x2 a = new Matrix3x2(); a.M11 = 5.0f; a.M12 = 2.0f; a.M21 = 12.0f; a.M22 = 6.8f; a.M31 = 6.5f; a.M32 = 1.0f; Matrix3x2 i; Assert.IsTrue(Matrix3x2.Invert(a, out i)); float detA = a.GetDeterminant(); float detI = i.GetDeterminant(); float t = 1.0f / detI; // only accurate to 3 precision Assert.IsTrue(System.Math.Abs(detA - t) < 1e-3, "Matrix3x2.GetDeterminant was not set correctly."); // sanity check against 4x4 version Assert.AreEqual(new Matrix4x4(a).GetDeterminant(), detA); Assert.AreEqual(new Matrix4x4(i).GetDeterminant(), detI); }
private Matrix3x2 unNormScreen; // just flip Y public void CalcultateMatrixes() { worldToScreenAndFlipY = Matrix3x2.CreateTranslation(-PositionInWorldCoordinates.X, -PositionInWorldCoordinates.Y) * Matrix3x2.CreateScale(new Vector2(Zoom.X, Zoom.Y)) * // Y up is plus Matrix3x2.CreateScale(GraphAreaSize) * Matrix3x2.CreateTranslation(GraphAreaSize.X / 2 + GraphOffsetInPx.X, GraphAreaSize.Y / 2 + GraphOffsetInPx.Y) * // move 0,0 corner in pix from upper left corner to lower, left corner Matrix3x2.CreateScale(new Vector2(1, -1)) * Matrix3x2.CreateTranslation(new Vector2(0, ImageSize.Y)); worldToScreen = Matrix3x2.CreateTranslation(-PositionInWorldCoordinates.X, -PositionInWorldCoordinates.Y) * Matrix3x2.CreateScale(new Vector2(Zoom.X, Zoom.Y)) * // Y up is plus Matrix3x2.CreateScale(GraphAreaSize) * Matrix3x2.CreateTranslation(GraphAreaSize.X / 2 + GraphOffsetInPx.X, GraphAreaSize.Y / 2 + GraphOffsetInPx.Y); normScreen = Matrix3x2.CreateScale(new Vector2(1, -1)) * Matrix3x2.CreateTranslation(new Vector2(0, ImageSize.Y)); Matrix3x2.Invert(worldToScreen, out screenToWorld); Matrix3x2.Invert(worldToScreenAndFlipY, out screenToWorldAndFlipY); Matrix3x2.Invert(normScreen, out unNormScreen); }
public void Matrix3x2InvertTest1() { Matrix3x2 a = new Matrix3x2(); a.M11 = 0.0f; a.M12 = 2.0f; a.M21 = 0.0f; a.M22 = 4.0f; a.M31 = 5.0f; a.M32 = 6.0f; float detA = a.GetDeterminant(); Assert.IsTrue(MathHelper.Equal(detA, 0.0f), "Matrix3x2.Invert did not return the expected value."); Matrix3x2 actual; Assert.IsFalse(Matrix3x2.Invert(a, out actual)); // all the elements in Actual is NaN Assert.IsTrue( float.IsNaN(actual.M11) && float.IsNaN(actual.M12) && float.IsNaN(actual.M21) && float.IsNaN(actual.M22) && float.IsNaN(actual.M31) && float.IsNaN(actual.M32) , "Matrix3x2.Invert did not return the expected value."); }
public void OnManipulationSelectFinished(object sender, bool blendCurrentStroke) { List <List <Vector2> > clonedSimpl = new List <List <Vector2> >(VectorInkBuilder.PolygonSimplifier.AllData); List <List <Vector2> > mergedPolygons = PolygonUtils.MergePolygons(clonedSimpl); if (!TransformationMatrix.IsIdentity) { bool res = Matrix3x2.Invert(TransformationMatrix, out Matrix3x2 viewToModelTransformationMatrix); if (!res) { throw new InvalidOperationException("Transform matrix could not be inverted."); } TransformUtils.TransformPolysXY(mergedPolygons, viewToModelTransformationMatrix); } // NOTE: If ManipulationMode is PartialStroke, affected strokes are deleted and new strokes created // for selected and non-selected portions. This occurs BEFORE any manipulation takes place. // Reverting to previous state in the event of no manipulation taking place requires // undo functionality (delete added strokes, restore deleted strokes) mSpatialModel.Select(mergedPolygons[0], mSelectTool.ManipulationMode); }
private void OnRenderFormMouseClick(object sender, System.Windows.Forms.MouseEventArgs e) { // Mouse clicks are in "screen space". DirectX might be rendering the client/form in a different resolution (i.e., "world space") // so we need to transform the click coordinates from "screen space" to "world space". // It gets trickier. We want to know what facial point is clicked on. The facial point coordinates exist in "local/object space". They // were transformed to "world space" prior to being rendered. So, we need to transform the mouse click coordinates from "world space" to // the facial point "local/object space". Matrix3x2 inverseOfRenderTargetTransform = new Matrix3x2(); Matrix3x2.Invert(ref this.transformation, out inverseOfRenderTargetTransform); Size2F renderTargetSize = this.d2dRenderTarget.Size; System.Drawing.Rectangle clientSize = this.renderForm.ClientRectangle; float scalingFromClientToRenderTargetX = renderTargetSize.Width / clientSize.Right; float scalingFromClientToRenderTargetY = renderTargetSize.Height / clientSize.Bottom; Vector2 renderTargetClickCoord = new Vector2(e.X * scalingFromClientToRenderTargetX, e.Y * scalingFromClientToRenderTargetY); Vector2 transformedRenderTargetClickCoord = Matrix3x2.TransformPoint(inverseOfRenderTargetTransform, renderTargetClickCoord); RectangleF transformedRenderTargetClickArea = new RectangleF(transformedRenderTargetClickCoord.X, transformedRenderTargetClickCoord.Y, ClickSize, ClickSize); this.selectedFacePointIndex = null; for (int pointIndex = 0; pointIndex < this.facePoints.Length; pointIndex++) { if (transformedRenderTargetClickArea.Contains(this.facePoints[pointIndex])) { this.selectedFacePointIndex = pointIndex; break; } } this.selectedFacePointTimeout = this.framesPerSecond.RunTime.Add(new TimeSpan(0, 0, EventTimeoutSeconds)); }
public void Matrix3x2InvertTest() { Matrix3x2 mtx = Matrix3x2.CreateRotation(MathHelper.ToRadians(30.0f)); Matrix3x2 expected = new Matrix3x2(); expected.M11 = 0.8660254f; expected.M12 = -0.5f; expected.M21 = 0.5f; expected.M22 = 0.8660254f; expected.M31 = 0; expected.M32 = 0; Matrix3x2 actual; Assert.True(Matrix3x2.Invert(mtx, out actual)); Assert.True(MathHelper.Equal(expected, actual), "Matrix3x2.Invert did not return the expected value."); Matrix3x2 i = mtx * actual; Assert.True(MathHelper.Equal(i, Matrix3x2.Identity), "Matrix3x2.Invert did not return the expected value."); }
/// <inheritdoc/> protected override void OnFrameApply( ImageFrame <TPixel> source, ImageFrame <TPixel> destination, Rectangle sourceRectangle, Configuration configuration) { int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; Rectangle sourceBounds = source.Bounds(); var targetBounds = new Rectangle(0, 0, width, height); // Since could potentially be resizing the canvas we might need to re-calculate the matrix Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); // Convert from screen to world space. Matrix3x2.Invert(matrix, out matrix); if (this.Sampler is NearestNeighborResampler) { ParallelHelper.IterateRows( targetBounds, configuration, rows => { for (int y = rows.Min; y < rows.Max; y++) { Span <TPixel> destRow = destination.GetPixelRowSpan(y); for (int x = 0; x < width; x++) { var point = Point.Transform(new Point(x, y), matrix); if (sourceBounds.Contains(point.X, point.Y)) { destRow[x] = source[point.X, point.Y]; } } } }); return; } int maxSourceX = source.Width - 1; int maxSourceY = source.Height - 1; (float radius, float scale, float ratio)xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); (float radius, float scale, float ratio)yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); float xScale = xRadiusScale.scale; float yScale = yRadiusScale.scale; var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); IResampler sampler = this.Sampler; var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); MemoryAllocator memoryAllocator = configuration.MemoryAllocator; using (Buffer2D <float> yBuffer = memoryAllocator.Allocate2D <float>(yLength, height)) using (Buffer2D <float> xBuffer = memoryAllocator.Allocate2D <float>(xLength, height)) { ParallelHelper.IterateRows( targetBounds, configuration, rows => { for (int y = rows.Min; y < rows.Max; y++) { ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); for (int x = 0; x < width; x++) { // Use the single precision position to calculate correct bounding pixels // otherwise we get rogue pixels outside of the bounds. var point = Vector2.Transform(new Vector2(x, y), matrix); // Clamp sampling pixel radial extents to the source image edges Vector2 maxXY = point + radius; Vector2 minXY = point - radius; // max, maxY, minX, minY var extents = new Vector4( MathF.Floor(maxXY.X + .5F), MathF.Floor(maxXY.Y + .5F), MathF.Ceiling(minXY.X - .5F), MathF.Ceiling(minXY.Y - .5F)); int right = (int)extents.X; int bottom = (int)extents.Y; int left = (int)extents.Z; int top = (int)extents.W; extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); int maxX = (int)extents.X; int maxY = (int)extents.Y; int minX = (int)extents.Z; int minY = (int)extents.W; if (minX == maxX || minY == maxY) { continue; } // It appears these have to be calculated on-the-fly. // Precalculating transformed weights would require prior knowledge of every transformed pixel location // since they can be at sub-pixel positions on both axis. // I've optimized where I can but am always open to suggestions. if (yScale > 1 && xScale > 1) { CalculateWeightsDown( top, bottom, minY, maxY, point.Y, sampler, yScale, ref ySpanRef, yLength); CalculateWeightsDown( left, right, minX, maxX, point.X, sampler, xScale, ref xSpanRef, xLength); } else { CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); } // Now multiply the results against the offsets Vector4 sum = Vector4.Zero; for (int yy = 0, j = minY; j <= maxY; j++, yy++) { float yWeight = Unsafe.Add(ref ySpanRef, yy); for (int xx = 0, i = minX; i <= maxX; i++, xx++) { float xWeight = Unsafe.Add(ref xSpanRef, xx); // Values are first premultiplied to prevent darkening of edge pixels var current = source[i, j].ToVector4(); Vector4Utils.Premultiply(ref current); sum += current * xWeight * yWeight; } } ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); // Reverse the premultiplication Vector4Utils.UnPremultiply(ref sum); dest.FromVector4(sum); }
/// <inheritdoc/> protected override void OnFrameApply( ImageFrame <TPixel> source, ImageFrame <TPixel> destination, Rectangle sourceRectangle, Configuration configuration) { int height = this.TargetDimensions.Height; int width = this.TargetDimensions.Width; Rectangle sourceBounds = source.Bounds(); var targetBounds = new Rectangle(0, 0, width, height); // Since could potentially be resizing the canvas we might need to re-calculate the matrix Matrix3x2 matrix = this.GetProcessingMatrix(sourceBounds, targetBounds); // Convert from screen to world space. Matrix3x2.Invert(matrix, out matrix); if (this.Sampler is NearestNeighborResampler) { Parallel.For( 0, height, configuration.ParallelOptions, y => { Span <TPixel> destRow = destination.GetPixelRowSpan(y); for (int x = 0; x < width; x++) { var point = Point.Transform(new Point(x, y), matrix); if (sourceBounds.Contains(point.X, point.Y)) { destRow[x] = source[point.X, point.Y]; } } }); return; } int maxSourceX = source.Width - 1; int maxSourceY = source.Height - 1; (float radius, float scale, float ratio)xRadiusScale = this.GetSamplingRadius(source.Width, destination.Width); (float radius, float scale, float ratio)yRadiusScale = this.GetSamplingRadius(source.Height, destination.Height); float xScale = xRadiusScale.scale; float yScale = yRadiusScale.scale; var radius = new Vector2(xRadiusScale.radius, yRadiusScale.radius); IResampler sampler = this.Sampler; var maxSource = new Vector4(maxSourceX, maxSourceY, maxSourceX, maxSourceY); int xLength = (int)MathF.Ceiling((radius.X * 2) + 2); int yLength = (int)MathF.Ceiling((radius.Y * 2) + 2); MemoryManager memoryManager = configuration.MemoryManager; using (Buffer2D <float> yBuffer = memoryManager.Allocate2D <float>(yLength, height)) using (Buffer2D <float> xBuffer = memoryManager.Allocate2D <float>(xLength, height)) { Parallel.For( 0, height, configuration.ParallelOptions, y => { ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y));
public bool InvertBenchmark() => Matrix3x2.Invert(Matrix3x2.Identity, out Matrix3x2 result);
public static Matrix3x2 Invert(this Matrix3x2 matrix) { return(Matrix3x2.Invert(matrix)); }
public Vector2 InvertTransformPoint(Matrix3x2 matrix, Vector2 point) { matrix.Invert(); return(Matrix3x2.TransformPoint(matrix, point)); }
/// <summary> /// Gets the tile at the location given. /// </summary> /// <param name="location">The location.</param> /// <returns></returns> private TileBase GetTileOver(Vector2 location) { Dictionary <Tile, IGraphicsPath> tilePaths = new Dictionary <Tile, IGraphicsPath>(); try { Matrix3x2 inverseViewMatrix = Controller.View.InverseViewMatrix; IEnumerable <TileBase> tiles = Controller.Tiles; foreach (TileBase tile in tiles) { IGraphicsPath path; bool disposePath = false; TileInstance tileInstance; Tile rawTile = tile as Tile; if (rawTile != null) { path = new GDIGraphics.GraphicsPath(); rawTile.PopulateGraphicsPath(path); tilePaths.Add(rawTile, path); } else if ((tileInstance = tile as TileInstance) != null) { if (!tilePaths.TryGetValue(tileInstance.Tile, out path)) { path = new GDIGraphics.GraphicsPath(); tileInstance.Tile.PopulateGraphicsPath(path); tilePaths.Add(tileInstance.Tile, path); } Debug.Assert(path != null, "path != null"); } else { disposePath = true; path = new GDIGraphics.GraphicsPath(); tile.PopulateGraphicsPath(path); } using (disposePath ? path : null) { Matrix3x2 tranform; if (Matrix3x2.Invert(tile.Transform, out tranform) && path.ContainsPoint(location, inverseViewMatrix * tranform)) { return(tile); } } } } finally { foreach (IGraphicsPath path in tilePaths.Values) { Debug.Assert(path != null, "path != null"); path.Dispose(); } } Debug.Fail("There should be a tile"); return(null); }
static Matrix3x2 Inverse(Matrix3x2 m) { Matrix3x2.Invert(m, out var r); return(r); }