public static CGPath ToCGPath( this PathF target) { var path = new CGPath(); int pointIndex = 0; int arcAngleIndex = 0; int arcClockwiseIndex = 0; foreach (var operation in target.PathOperations) { if (operation == PathOperation.MoveTo) { var point = target[pointIndex++]; path.MoveToPoint(point.X, point.Y); } else if (operation == PathOperation.Line) { var endPoint = target[pointIndex++]; path.AddLineToPoint(endPoint.X, endPoint.Y); } else if (operation == PathOperation.Quad) { var controlPoint = target[pointIndex++]; var endPoint = target[pointIndex++]; path.AddQuadCurveToPoint( controlPoint.X, controlPoint.Y, endPoint.X, endPoint.Y); } else if (operation == PathOperation.Cubic) { var controlPoint1 = target[pointIndex++]; var controlPoint2 = target[pointIndex++]; var endPoint = target[pointIndex++]; path.AddCurveToPoint( controlPoint1.X, controlPoint1.Y, controlPoint2.X, controlPoint2.Y, endPoint.X, endPoint.Y); } else if (operation == PathOperation.Arc) { var topLeft = target[pointIndex++]; var bottomRight = target[pointIndex++]; float startAngle = target.GetArcAngle(arcAngleIndex++); float endAngle = target.GetArcAngle(arcAngleIndex++); var clockwise = target.IsArcClockwise(arcClockwiseIndex++); var startAngleInRadians = GraphicsOperations.DegreesToRadians(-startAngle); var endAngleInRadians = GraphicsOperations.DegreesToRadians(-endAngle); while (startAngleInRadians < 0) { startAngleInRadians += (float)Math.PI * 2; } while (endAngleInRadians < 0) { endAngleInRadians += (float)Math.PI * 2; } var cx = (bottomRight.X + topLeft.X) / 2; var cy = (bottomRight.Y + topLeft.Y) / 2; var width = bottomRight.X - topLeft.X; var height = bottomRight.Y - topLeft.Y; var r = width / 2; var transform = CGAffineTransform.MakeTranslation(cx, cy); transform = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(1, height / width), transform); path.AddArc(transform, 0, 0, r, startAngleInRadians, endAngleInRadians, !clockwise); } else if (operation == PathOperation.Close) { path.CloseSubpath(); } } return(path); }
public static CGPath AsRotatedCGPath(this PathF target, PointF center, float ppu, float zoom, float angle) { ppu = ppu * zoom; var path = new CGPath(); int pointIndex = 0; int arcAngleIndex = 0; int arcClockwiseIndex = 0; foreach (var type in target.SegmentTypes) { if (type == PathOperation.Move) { var point = target.GetRotatedPoint(pointIndex++, center, angle); path.MoveToPoint(point.X * ppu, point.Y * ppu); } else if (type == PathOperation.Line) { var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); path.AddLineToPoint(endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Quad) { var controlPoint = target.GetRotatedPoint(pointIndex++, center, angle); var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); path.AddQuadCurveToPoint( controlPoint.X * ppu, controlPoint.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Cubic) { var controlPoint1 = target.GetRotatedPoint(pointIndex++, center, angle); var controlPoint2 = target.GetRotatedPoint(pointIndex++, center, angle); var endPoint = target.GetRotatedPoint(pointIndex++, center, angle); path.AddCurveToPoint( controlPoint1.X * ppu, controlPoint1.Y * ppu, controlPoint2.X * ppu, controlPoint2.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Arc) { var topLeft = target[pointIndex++]; var bottomRight = target[pointIndex++]; float startAngle = target.GetArcAngle(arcAngleIndex++); float endAngle = target.GetArcAngle(arcAngleIndex++); var clockwise = target.GetArcClockwise(arcClockwiseIndex++); var startAngleInRadians = Geometry.DegreesToRadians(-startAngle); var endAngleInRadians = Geometry.DegreesToRadians(-endAngle); while (startAngleInRadians < 0) { startAngleInRadians += (float)Math.PI * 2; } while (endAngleInRadians < 0) { endAngleInRadians += (float)Math.PI * 2; } var cx = (bottomRight.X + topLeft.X) / 2; var cy = (bottomRight.Y + topLeft.Y) / 2; var width = bottomRight.X - topLeft.X; var height = bottomRight.Y - topLeft.Y; var r = width / 2; var rotatedCenter = Geometry.RotatePoint(center, new PointF(cx, cy), angle); var transform = CGAffineTransform.MakeTranslation(rotatedCenter.X * ppu, rotatedCenter.Y * ppu); transform = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(1, height / width), transform); path.AddArc(transform, 0, 0, r * ppu, startAngleInRadians, endAngleInRadians, !clockwise); } else if (type == PathOperation.Close) { path.CloseSubpath(); } } return(path); }
public static CGPath AsCGPath( this PathF target, float ox, float oy, float fx, float fy) { var path = new CGPath(); int pointIndex = 0; int arcAngleIndex = 0; int arcClockwiseIndex = 0; foreach (var type in target.SegmentTypes) { if (type == PathOperation.Move) { var point = target[pointIndex++]; path.MoveToPoint((ox + point.X * fx), (oy + point.Y * fy)); } else if (type == PathOperation.Line) { var endPoint = target[pointIndex++]; path.AddLineToPoint((ox + endPoint.X * fx), (oy + endPoint.Y * fy)); } else if (type == PathOperation.Quad) { var controlPoint = target[pointIndex++]; var endPoint = target[pointIndex++]; path.AddQuadCurveToPoint( (ox + controlPoint.X * fx), (oy + controlPoint.Y * fy), (ox + endPoint.X * fx), (oy + endPoint.Y * fy)); } else if (type == PathOperation.Cubic) { var controlPoint1 = target[pointIndex++]; var controlPoint2 = target[pointIndex++]; var endPoint = target[pointIndex++]; path.AddCurveToPoint( (ox + controlPoint1.X * fx), (oy + controlPoint1.Y * fy), (ox + controlPoint2.X * fx), (oy + controlPoint2.Y * fy), (ox + endPoint.X * fx), (oy + endPoint.Y * fy)); } else if (type == PathOperation.Arc) { var topLeft = target[pointIndex++]; var bottomRight = target[pointIndex++]; float startAngle = target.GetArcAngle(arcAngleIndex++); float endAngle = target.GetArcAngle(arcAngleIndex++); var clockwise = target.GetArcClockwise(arcClockwiseIndex++); var startAngleInRadians = Geometry.DegreesToRadians(-startAngle); var endAngleInRadians = Geometry.DegreesToRadians(-endAngle); while (startAngleInRadians < 0) { startAngleInRadians += (float)Math.PI * 2; } while (endAngleInRadians < 0) { endAngleInRadians += (float)Math.PI * 2; } var cx = (bottomRight.X + topLeft.X) / 2; var cy = (bottomRight.Y + topLeft.Y) / 2; var width = bottomRight.X - topLeft.X; var height = bottomRight.Y - topLeft.Y; var r = width / 2; var transform = CGAffineTransform.MakeTranslation(ox + cx, oy + cy); transform = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(1, height / width), transform); path.AddArc(transform, 0, 0, r * fx, startAngleInRadians, endAngleInRadians, !clockwise); } else if (type == PathOperation.Close) { path.CloseSubpath(); } } return(path); }
public void Shear(float shearX, float shearY, MatrixOrder order) { var affine = new CGAffineTransform (1, shearY, shearX, 1, 0, 0); if (order == MatrixOrder.Append) transform.Multiply (affine); else { affine.Multiply (transform); transform = affine; } }
public static CGPath AsCGPathFromSegment( this PathF target, int segmentIndex, float ppu, float zoom) { ppu = ppu * zoom; var path = new CGPath(); var type = target.GetSegmentType(segmentIndex); if (type == PathOperation.Line) { var pointIndex = target.GetSegmentPointIndex(segmentIndex); var startPoint = target[pointIndex - 1]; path.MoveToPoint(startPoint.X * ppu, startPoint.Y * ppu); var endPoint = target[pointIndex]; path.AddLineToPoint(endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Quad) { var pointIndex = target.GetSegmentPointIndex(segmentIndex); var startPoint = target[pointIndex - 1]; path.MoveToPoint(startPoint.X * ppu, startPoint.Y * ppu); var controlPoint = target[pointIndex++]; var endPoint = target[pointIndex]; path.AddQuadCurveToPoint(controlPoint.X * ppu, controlPoint.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Cubic) { var pointIndex = target.GetSegmentPointIndex(segmentIndex); var startPoint = target[pointIndex - 1]; path.MoveToPoint(startPoint.X * ppu, startPoint.Y * ppu); var controlPoint1 = target[pointIndex++]; var controlPoint2 = target[pointIndex++]; var endPoint = target[pointIndex]; path.AddCurveToPoint(controlPoint1.X * ppu, controlPoint1.Y * ppu, controlPoint2.X * ppu, controlPoint2.Y * ppu, endPoint.X * ppu, endPoint.Y * ppu); } else if (type == PathOperation.Arc) { target.GetSegmentInfo(segmentIndex, out var pointIndex, out var arcAngleIndex, out var arcClockwiseIndex); var topLeft = target[pointIndex++]; var bottomRight = target[pointIndex++]; var startAngle = target.GetArcAngle(arcAngleIndex++); var endAngle = target.GetArcAngle(arcAngleIndex++); var clockwise = target.GetArcClockwise(arcClockwiseIndex++); var startAngleInRadians = Geometry.DegreesToRadians(-startAngle); var endAngleInRadians = Geometry.DegreesToRadians(-endAngle); while (startAngleInRadians < 0) { startAngleInRadians += (float)Math.PI * 2; } while (endAngleInRadians < 0) { endAngleInRadians += (float)Math.PI * 2; } var cx = (bottomRight.X + topLeft.X) / 2; var cy = (bottomRight.Y + topLeft.Y) / 2; var width = bottomRight.X - topLeft.X; var height = bottomRight.Y - topLeft.Y; var r = width / 2; var transform = CGAffineTransform.MakeTranslation(cx * ppu, cy * ppu); transform = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(1, height / width), transform); path.AddArc(transform, 0, 0, r * ppu, startAngleInRadians, endAngleInRadians, !clockwise); } return(path); }
public void RotateTransform(float angle) { angle = (float)CGConversions.DegreesToRadians(angle); Control.RotateCTM(angle); currentTransform = CGAffineTransform.Multiply(CGAffineTransform.MakeRotation(angle), currentTransform); }
/// <summary> /// Draws the specified Image at the specified location and with the specified shape and size. /// /// The destPoints parameter specifies three points of a parallelogram. The three PointF structures /// represent the upper-left, upper-right, and lower-left corners of the parallelogram. The fourth point /// is extrapolated from the first three to form a parallelogram. /// /// The image represented by the image object is scaled and sheared to fit the shape of the parallelogram /// specified by the destPoints parameter. /// </summary> /// <param name="image">Image.</param> /// <param name="destPoints">Destination points.</param> public void DrawImage(Image image, PointF [] destPoints) { if (image == null) throw new ArgumentNullException ("image"); if (destPoints == null) throw new ArgumentNullException ("destPoints"); if (destPoints.Length < 3) throw new ArgumentException ("Destination points must be an array with a length of 3 or 4. " + "A length of 3 defines a parallelogram with the upper-left, upper-right, " + "and lower-left corners. A length of 4 defines a quadrilateral with the " + "fourth element of the array specifying the lower-right coordinate."); // Windows throws a Not Implemented error if the points are more than 3 if (destPoints.Length > 3) throw new NotImplementedException (); // create our rectangle. Offset is 0 because the CreateGeometricTransform bakes our x,y offset in there. var rect = new RectangleF (0,0, destPoints [1].X - destPoints [0].X, destPoints [2].Y - destPoints [0].Y); // We need to flip our Y axis so the image appears right side up var geoTransform = new CGAffineTransform (1, 0, 0, -1, 0, rect.Height); //var geott = GeomUtilities.CreateGeometricTransform (rect, destPoints); geoTransform.Multiply (GeomUtilities.CreateGeometricTransform (rect, destPoints)); // Apply our transform to the context context.ConcatCTM (geoTransform); // now we draw our image. context.DrawImage(rect.ToCGRect (), image.NativeCGImage); // Now we revert our image transform from the context var revert = CGAffineTransform.CGAffineTransformInvert (geoTransform); context.ConcatCTM (revert); }
public void Scale(float scaleX, float scaleY) { control = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(scaleX, scaleY), control); }
public void ScaleAt(float scaleX, float scaleY, float centerX, float centerY) { var matrix = new CGAffineTransform(scaleX, 0f, 0f, scaleY, centerX - centerX * scaleX, centerY - centerY * scaleY); control = CGAffineTransform.Multiply(matrix, control); }
public void Rotate(float angle) { control = CGAffineTransform.Multiply(CGAffineTransform.MakeRotation(Conversions.DegreesToRadians(angle)), control); }
public void Translate(float x, float y) { control = CGAffineTransform.Multiply(CGAffineTransform.MakeTranslation(x, y), control); }
/// <summary> /// Draws the specified portion of the specified Image at the specified location and with the specified size. /// /// The destPoints specifies a parallelogram with the first point specifying the upper left corner, /// second point specifying the upper right corner and the third point specifying the lower left corner. /// /// The srcRect parameter specifies a rectangular portion of the image object to draw. This portion is scaled /// up or down (in the case where source rectangle overruns the bounds of the image) to fit inside the rectangle /// specified by the destRect parameter. /// </summary> /// <param name="image">Image.</param> /// <param name="destPoints">Destination points.</param> /// <param name="srcRect">Source rect.</param> /// <param name="srcUnit">Source unit.</param> public void DrawImage(Image image, PointF [] destPoints, RectangleF srcRect, GraphicsUnit srcUnit) { if (image == null) { throw new ArgumentNullException("image"); } if (destPoints == null) { throw new ArgumentNullException("destPoints"); } if (destPoints.Length < 3) { throw new ArgumentException("Destination points must be an array with a length of 3 or 4. " + "A length of 3 defines a parallelogram with the upper-left, upper-right, " + "and lower-left corners. A length of 4 defines a quadrilateral with the " + "fourth element of the array specifying the lower-right coordinate."); } // Windows throws a Not Implemented error if the points are more than 3 if (destPoints.Length > 3) { throw new NotImplementedException(); } var srcRect1 = srcRect; // If the source units are not the same we need to convert them // The reason we check for Pixel here is that our graphics already has the Pixel's baked into the model view transform if (srcUnit != graphicsUnit && srcUnit != GraphicsUnit.Pixel) { ConversionHelpers.GraphicsUnitConversion(srcUnit, graphicsUnit, image.HorizontalResolution, image.VerticalResolution, ref srcRect1); } // Obtain the subImage var subImage = image.NativeCGImage.WithImageInRect(srcRect1); // If we do not have anything to draw then we exit here if (subImage.Width == 0 || subImage.Height == 0) { return; } // create our rectangle. Offset is 0 because the CreateGeometricTransform bakes our x,y offset in there. var rect = new RectangleF(0, 0, destPoints [1].X - destPoints [0].X, destPoints [2].Y - destPoints [0].Y); // We need to flip our Y axis so the image appears right side up var geoTransform = new CGAffineTransform(1, 0, 0, -1, 0, rect.Height); // Make sure we scale the image in case the source rectangle // overruns our subimage bounds (width and/or height) float scaleX = subImage.Width / srcRect1.Width; float scaleY = subImage.Height / srcRect1.Height; geoTransform.Scale(scaleX, scaleY); //var geott = GeomUtilities.CreateGeometricTransform (rect, destPoints); geoTransform.Multiply(GeomUtilities.CreateGeometricTransform(rect, destPoints)); // Apply our transform to the context context.ConcatCTM(geoTransform); // now we draw our image. context.DrawImage(rect, subImage); // Now we revert our image transform from the context var revert = CGAffineTransform.CGAffineTransformInvert(geoTransform); context.ConcatCTM(revert); }
public ESTexture2D(UIImage uiImage, All filter) { CGImage image = uiImage.CGImage; if (uiImage == null) { throw new ArgumentNullException("uiImage"); } // TODO: could use this to implement lower-bandwidth textures //bool hasAlpha = (image.AlphaInfo == CGImageAlphaInfo.First || image.AlphaInfo == CGImageAlphaInfo.Last // || image.AlphaInfo == CGImageAlphaInfo.PremultipliedFirst || image.AlphaInfo == CGImageAlphaInfo.PremultipliedLast); // Image dimentions: logicalSize = new Point((int)uiImage.Size.Width, (int)uiImage.Size.Height); pixelWidth = uiImage.CGImage.Width; pixelHeight = uiImage.CGImage.Height; // Round up the target texture width and height to powers of two: potWidth = pixelWidth; potHeight = pixelHeight; if ((potWidth & (potWidth - 1)) != 0) { int w = 1; while (w < potWidth) { w *= 2; } potWidth = w; } if ((potHeight & (potHeight - 1)) != 0) { int h = 1; while (h < potHeight) { h *= 2; } potHeight = h; } // Scale down textures that are too large... CGAffineTransform transform = CGAffineTransform.MakeIdentity(); while ((potWidth > 1024) || (potHeight > 1024)) { potWidth /= 2; // Note: no precision loss - it's a power of two potHeight /= 2; pixelWidth /= 2; // Note: precision loss - assume possibility of dropping a pixel at each step is ok pixelHeight /= 2; transform.Multiply(CGAffineTransform.MakeScale(0.5f, 0.5f)); } RecalculateRatio(); lock (textureLoadBufferLockObject) { CreateTextureLoadBuffer(); unsafe { fixed(byte *data = textureLoadBuffer) { var colorSpace = CGColorSpace.CreateDeviceRGB(); var context = new CGBitmapContext(new IntPtr(data), potWidth, potHeight, 8, 4 * potWidth, colorSpace, CGImageAlphaInfo.PremultipliedLast); context.ClearRect(new RectangleF(0, 0, potWidth, potHeight)); context.TranslateCTM(0, potHeight - pixelHeight); // TODO: this does not play nice with the precision-loss above (keeping half-pixel to the edge) if (!transform.IsIdentity) { context.ConcatCTM(transform); } context.DrawImage(new RectangleF(0, 0, image.Width, image.Height), image); SetupTexture(new IntPtr(data), filter); context.Dispose(); colorSpace.Dispose(); } } } }
public Matrix(RectangleF rect, PointF[] plgpts) { if (plgpts == null) throw new ArgumentNullException ("plgpts"); if (plgpts.Length != 3) throw new ArgumentException ("plgpts"); PointF p0 = plgpts [0]; PointF p1 = plgpts [1]; PointF p2 = plgpts [2]; float m11 = (p1.X - p0.X) / rect.Width; float m12 = (p1.Y - p0.Y) / rect.Width; float m21 = (p2.X - p0.X) / rect.Height; float m22 = (p2.Y - p0.Y) / rect.Height; transform = CGAffineTransform.MakeTranslation(-rect.X, -rect.Y); transform.Multiply(new CGAffineTransform (m11, m12, m21, m22, p0.X, p0.Y)); }
internal override void Setup(Graphics graphics, bool fill) { // if this is the same as the last that was set then return and no changes have been made // then return. if (graphics.LastBrush == this && !changed) { return; } // obtain our width and height so we can set the pattern rectangle float textureWidth = textureImage.Width; float textureHeight = textureImage.Height; if (wrapMode == WrapMode.TileFlipX || wrapMode == WrapMode.TileFlipY) { textureWidth *= 2; } if (wrapMode == WrapMode.TileFlipXY) { textureWidth *= 2; textureHeight *= 2; } //choose the pattern to be filled based on the currentPattern selected var patternSpace = CGColorSpace.CreatePattern(null); graphics.context.SetFillColorSpace(patternSpace); patternSpace.Dispose(); // Pattern default work variables var patternRect = new CGRect(HALF_PIXEL_X, HALF_PIXEL_Y, textureWidth + HALF_PIXEL_X, textureHeight + HALF_PIXEL_Y); var patternTransform = graphics.context.GetCTM(); patternTransform = CGAffineTransform.Multiply(patternTransform, new CGAffineTransform(1f / graphics.screenScale, 0, 0, 1f / graphics.screenScale, 0, 0)); patternTransform = CGAffineTransform.Multiply(textureTransform.transform, patternTransform); // DrawPattern callback which will be set depending on hatch style CGPattern.DrawPattern drawPattern; drawPattern = DrawTexture; //set the pattern as the Current Context’s fill pattern var pattern = new CGPattern(patternRect, patternTransform, textureWidth, textureHeight, //textureHeight, CGPatternTiling.NoDistortion, true, drawPattern); //we dont need to set any color, as the pattern cell itself has chosen its own color graphics.context.SetFillPattern(pattern, new nfloat[] { 1 }); changed = false; graphics.LastBrush = this; // I am setting this to be used for Text coloring in DrawString //graphics.lastBrushColor = foreColor; }
public void Skew(float skewX, float skewY) { var matrix = new CGAffineTransform(1, (nfloat)Math.Tan(Conversions.DegreesToRadians(skewX)), (nfloat)Math.Tan(Conversions.DegreesToRadians(skewY)), 1, 0, 0); control = CGAffineTransform.Multiply(matrix, control); }
public void TranslateTransform(float offsetX, float offsetY) { Control.TranslateCTM(offsetX, offsetY); currentTransform = CGAffineTransform.Multiply(CGAffineTransform.MakeTranslation(offsetX, offsetY), currentTransform); }
public void Append(IMatrix matrix) { var affineMatrix = (CGAffineTransform)matrix.ControlObject; control.Multiply(affineMatrix); }
public void ScaleTransform(float scaleX, float scaleY) { Control.ScaleCTM(scaleX, scaleY); currentTransform = CGAffineTransform.Multiply(CGAffineTransform.MakeScale(scaleX, scaleY), currentTransform); }
public void Prepend(IMatrix matrix) { var affineMatrix = (CGAffineTransform)matrix.ControlObject; control = CGAffineTransform.Multiply(affineMatrix, control); }
/// <summary> /// Draws the specified portion of the specified Image at the specified location and with the specified size. /// /// The destPoints specifies a parallelogram with the first point specifying the upper left corner, /// second point specifying the upper right corner and the third point specifying the lower left corner. /// /// The srcRect parameter specifies a rectangular portion of the image object to draw. This portion is scaled /// up or down (in the case where source rectangle overruns the bounds of the image) to fit inside the rectangle /// specified by the destRect parameter. /// </summary> /// <param name="image">Image.</param> /// <param name="destPoints">Destination points.</param> /// <param name="srcRect">Source rect.</param> /// <param name="srcUnit">Source unit.</param> public void DrawImage(Image image, PointF [] destPoints, RectangleF srcRect, GraphicsUnit srcUnit) { if (image == null) throw new ArgumentNullException ("image"); if (destPoints == null) throw new ArgumentNullException ("destPoints"); if (destPoints.Length < 3) throw new ArgumentException ("Destination points must be an array with a length of 3 or 4. " + "A length of 3 defines a parallelogram with the upper-left, upper-right, " + "and lower-left corners. A length of 4 defines a quadrilateral with the " + "fourth element of the array specifying the lower-right coordinate."); // Windows throws a Not Implemented error if the points are more than 3 if (destPoints.Length > 3) throw new NotImplementedException (); var srcRect1 = srcRect; // If the source units are not the same we need to convert them // The reason we check for Pixel here is that our graphics already has the Pixel's baked into the model view transform if (srcUnit != graphicsUnit && srcUnit != GraphicsUnit.Pixel) { ConversionHelpers.GraphicsUnitConversion (srcUnit, graphicsUnit, image.HorizontalResolution, image.VerticalResolution, ref srcRect1); } // Obtain the subImage var subImage = image.NativeCGImage.WithImageInRect (srcRect1.ToCGRect ()); // If we do not have anything to draw then we exit here if (subImage.Width == 0 || subImage.Height == 0) return; // create our rectangle. Offset is 0 because the CreateGeometricTransform bakes our x,y offset in there. var rect = new RectangleF (0,0, destPoints [1].X - destPoints [0].X, destPoints [2].Y - destPoints [0].Y); // We need to flip our Y axis so the image appears right side up var geoTransform = new CGAffineTransform (1, 0, 0, -1, 0, rect.Height); // Make sure we scale the image in case the source rectangle // overruns our subimage bounds (width and/or height) float scaleX = subImage.Width/srcRect1.Width; float scaleY = subImage.Height/srcRect1.Height; geoTransform.Scale (scaleX, scaleY); //var geott = GeomUtilities.CreateGeometricTransform (rect, destPoints); geoTransform.Multiply (GeomUtilities.CreateGeometricTransform (rect, destPoints)); // Apply our transform to the context context.ConcatCTM (geoTransform); // now we draw our image. context.DrawImage(rect.ToCGRect (), subImage); // Now we revert our image transform from the context var revert = CGAffineTransform.CGAffineTransformInvert (geoTransform); context.ConcatCTM (revert); }
public iOSInspectView(UIView view, bool withSubviews = true) { if (view == null) { throw new ArgumentNullException(nameof(view)); } this.view = view; PopulateTypeInformationFromObject(view); // FIXME: special case certain view types and fill in the Description property if (view is UILabel) { Description = ((UILabel)view).Text; } else if (view is UIButton) { Description = ((UIButton)view).TitleLabel.Text; } else if (view is UITextField) { Description = ((UITextField)view).Text; } if (!view.Transform.IsIdentity) { var transform = CGAffineTransform.MakeIdentity(); transform.Translate(-view.Bounds.Width * .5f, -view.Bounds.Height * .5f); transform = CGAffineTransform.Multiply(transform, view.Transform); transform.Translate(view.Center.X, view.Center.Y); Transform = new ViewTransform { M11 = transform.xx, M12 = transform.yx, M21 = transform.xy, M22 = transform.yy, OffsetX = transform.x0, OffsetY = transform.y0 }; X = view.Bounds.X; Y = view.Bounds.Y; Width = view.Bounds.Width; Height = view.Bounds.Height; } else { X = view.Frame.X; Y = view.Frame.Y; Width = view.Frame.Width; Height = view.Frame.Height; } Kind = ViewKind.Primary; Visibility = view.Hidden ? ViewVisibility.Collapsed : ViewVisibility.Visible; if (!withSubviews) { var point = view.ConvertPointToView( new CoreGraphics.CGPoint(0, 0), null); X = point.X; Y = point.Y; return; } // MKMapView has a subview that is so large (5901507x5901507 in the case encountered) // that it causes the SceneKit camera to zoom out so much that every other node is // effectively hidden. This should ideally be fixed in the client. if (view is MapKit.MKMapView) { return; } var visitedLayers = new HashSet <IntPtr> (); var subviews = view.Subviews; if (subviews != null && subviews.Length > 0) { for (int i = 0; i < subviews.Length; i++) { var subview = new iOSInspectView(subviews [i]); AddSubview(subview); if (subview.Layer == null) { continue; } // After calling AddSubview, add any visited layers to the list. We track // visited layers here so that when we actually recurse into the layer that // belongs to this view, we don't duplicate things. This is needed because of // the pointer-into-a-tree nature of layers, as explained above in the constructor // remarks. var subviewLayer = (iOSInspectView)subview.Layer; if (subviewLayer.layer != null) { visitedLayers.Add(subviewLayer.layer.Handle); } subviewLayer.layer?.Sublayers?.ForEach( layer => visitedLayers.Add(layer.Handle)); } } if (view.Layer != null && !visitedLayers.Contains(view.Layer.Handle)) { Layer = new iOSInspectView(view, view.Layer, visitedLayers) { Parent = this } } ; }