def testFunctions(self): tf = Quartz.CGAffineTransformMake(1.5, 2.5, 3.5, 4.5, 5.5, 6.5) self.assertIsInstance(tf, Quartz.CGAffineTransform) self.assertEqual(tf.a, 1.5) self.assertEqual(tf.b, 2.5) self.assertEqual(tf.c, 3.5) self.assertEqual(tf.d, 4.5) self.assertEqual(tf.tx, 5.5) self.assertEqual(tf.ty, 6.5) tf = Quartz.CGAffineTransformMakeTranslation(2.5, 3.5) self.assertIsInstance(tf, Quartz.CGAffineTransform) self.assertEqual(tf.a, 1.0) self.assertEqual(tf.b, 0.0) self.assertEqual(tf.c, 0.0) self.assertEqual(tf.d, 1.0) self.assertEqual(tf.tx, 2.5) self.assertEqual(tf.ty, 3.5) tf = Quartz.CGAffineTransformMakeScale(2.5, 3.5) self.assertIsInstance(tf, Quartz.CGAffineTransform) self.assertEqual(tf.a, 2.5) self.assertEqual(tf.b, 0.0) self.assertEqual(tf.c, 0.0) self.assertEqual(tf.d, 3.5) self.assertEqual(tf.tx, 0.0) self.assertEqual(tf.ty, 0.0) tf = Quartz.CGAffineTransformMakeRotation(3.4) self.assertIsInstance(tf, Quartz.CGAffineTransform) self.assertResultHasType(Quartz.CGAffineTransformIsIdentity, objc._C_BOOL) self.assertTrue(Quartz.CGAffineTransformIsIdentity(tf) is False) self.assertTrue( Quartz.CGAffineTransformIsIdentity(Quartz.CGAffineTransformIdentity) is True ) tf = Quartz.CGAffineTransformTranslate(tf, 2.5, 3.5) self.assertIsInstance(tf, Quartz.CGAffineTransform) tf = Quartz.CGAffineTransformScale(tf, 5.5, 9.5) self.assertIsInstance(tf, Quartz.CGAffineTransform) tf = Quartz.CGAffineTransformRotate(tf, 0.8) self.assertIsInstance(tf, Quartz.CGAffineTransform) tf = Quartz.CGAffineTransformInvert(tf) self.assertIsInstance(tf, Quartz.CGAffineTransform) tf2 = Quartz.CGAffineTransformConcat( tf, Quartz.CGAffineTransformMake(1.0, 1.0, 1.0, 1.0, 1.0, 1.0) ) self.assertIsInstance(tf2, Quartz.CGAffineTransform) self.assertResultHasType(Quartz.CGAffineTransformEqualToTransform, objc._C_BOOL) self.assertTrue(Quartz.CGAffineTransformEqualToTransform(tf, tf2) is False) self.assertTrue(Quartz.CGAffineTransformEqualToTransform(tf2, tf2) is True) pt = Quartz.CGPointApplyAffineTransform((2.5, 3.5), tf) self.assertIsInstance(pt, Quartz.CGPoint) sz = Quartz.CGSizeApplyAffineTransform((2.5, 3.5), tf) self.assertIsInstance(sz, Quartz.CGSize) rct = Quartz.CGRectApplyAffineTransform(((2.5, 3.5), (4.5, 5.5)), tf) self.assertIsInstance(rct, Quartz.CGRect)
def drawRect_(self, rect): currentContext = Cocoa.NSGraphicsContext.currentContext().graphicsPort( ) # Note that at this point the current context CTM is set up such # that the context size corresponds to the size of the view # i.e. one unit in the context == one pixel # Also, the origin is in the bottom left of the view with +y pointing up global getFunction bounds = self.bounds() angle = 0 sx = sy = 1 width = bounds.size.width height = bounds.size.height if getFunction is None: self.randomize_(self) m = Quartz.CGAffineTransformIdentity m = Quartz.CGAffineTransformRotate(m, angle) m = Quartz.CGAffineTransformScale(m, width, height) m = Quartz.CGAffineTransformScale(m, sx, sy) Quartz.CGContextBeginPage(currentContext, bounds) Quartz.CGContextTranslateCTM(currentContext, bounds.size.width / 2, bounds.size.height / 2) Quartz.CGContextConcatCTM(currentContext, m) Quartz.CGContextTranslateCTM(currentContext, -0.5, -0.5) Quartz.CGContextSaveGState(currentContext) Quartz.CGContextClipToRect(currentContext, Quartz.CGRectMake(0, 0, 1, 1)) Quartz.CGContextSetRGBFillColor(currentContext, 0.7, 0.7, 0.9, 1) Quartz.CGContextFillRect(currentContext, Quartz.CGRectMake(0, 0, 1, 1)) Quartz.CGContextDrawShading(currentContext, shading) Quartz.CGContextRestoreGState(currentContext) Quartz.CGContextSaveGState(currentContext) Quartz.CGContextClipToRect(currentContext, Quartz.CGRectMake(0, 0, 1, 1)) Quartz.CGContextSetRGBStrokeColor(currentContext, 1, 0, 0, 1) if (getShading == getRadialShading): Quartz.CGContextAddArc(currentContext, startPoint.x, startPoint.y, startRadius, math.radians(0), math.radians(360), True) Quartz.CGContextClosePath(currentContext) Quartz.CGContextMoveToPoint(currentContext, endPoint.x + endRadius, endPoint.y) Quartz.CGContextAddArc(currentContext, endPoint.x, endPoint.y, endRadius, math.radians(0), math.radians(360), True) Quartz.CGContextClosePath(currentContext) Quartz.CGContextMoveToPoint(currentContext, startPoint.x + 0.01, startPoint.y) Quartz.CGContextAddArc(currentContext, startPoint.x, startPoint.y, 0.01, math.radians(0), math.radians(360), True) Quartz.CGContextClosePath(currentContext) Quartz.CGContextMoveToPoint(currentContext, startPoint.x, startPoint.y) Quartz.CGContextAddLineToPoint(currentContext, endPoint.x, endPoint.y) ctm = Quartz.CGContextGetCTM(currentContext) Quartz.CGContextConcatCTM(currentContext, Quartz.CGAffineTransformInvert(ctm)) Quartz.CGContextStrokePath(currentContext) Quartz.CGContextRestoreGState(currentContext) Quartz.CGContextSaveGState(currentContext) Quartz.CGContextSetGrayStrokeColor(currentContext, 0, 1) Quartz.CGContextAddRect(currentContext, Quartz.CGRectMake(0, 0, 1, 1)) ctm = Quartz.CGContextGetCTM(currentContext) Quartz.CGContextConcatCTM(currentContext, Quartz.CGAffineTransformInvert(ctm)) Quartz.CGContextStrokePath(currentContext) Quartz.CGContextRestoreGState(currentContext) Quartz.CGContextEndPage(currentContext) Quartz.CGContextFlush(currentContext)
def doEllipseShading(context): black = [0, 0, 0] red = [1, 0, 0] # This function describes a color ramp where the starting color # is red, the ending color is black. redBlackFunction = createFunctionWithStartEndColorRamp(red, black) if redBlackFunction is None: print("Couldn't create the red-black function!") return Quartz.CGContextTranslateCTM(context, 100, 300) # Shading 1. # To obtain an elliptical shading requires that user space # at the time the shading is painted is transformed so that # the circles which define the radial shading geometry are # rotated and elliptical. User space will be rotated # by 45 degrees, then scaled by 1 in x and 2 in y to produce # the ellipses. # Compute the transform needed to create the rotated ellipses. t = Quartz.CGAffineTransformMakeRotation(Utilities.DEGREES_TO_RADIANS(45)) t = Quartz.CGAffineTransformScale(t, 1, 2) circleACenter = Quartz.CGPoint(x=0, y=0) circleBCenter = Quartz.CGPoint(x=circleACenter.x + 144, y=circleACenter.y) circleARadius = 45 circleBRadius = 45 # Don't extend this shading. extendStart = extendEnd = False shading = Quartz.CGShadingCreateRadial( Utilities.getTheCalibratedRGBColorSpace(), circleACenter, circleARadius, circleBCenter, circleBRadius, redBlackFunction, extendStart, extendEnd) if shading is None: # Couldn't create the shading so release # the function before returning. print("Couldn't create the shading!") return Quartz.CGContextSaveGState(context) if 1: # Transform coordinates for the drawing of the shading. # This transform produces the rotated elliptical shading. # This produces the left shading in the figure, the # one where both the ellipses and the shading are # rotated relative to default user space. Quartz.CGContextConcatCTM(context, t) Quartz.CGContextDrawShading(context, shading) del shading Quartz.CGContextRestoreGState(context) Quartz.CGContextTranslateCTM(context, 300, 10) # Shading 2. # Now draw the shading where the shading ellipses are # rotated but the axis between the origins of # the ellipses lies parallel to the x axis in default # user space. This is similar to the shading drawn # manually in Chapter 5. # # To compute the correct origins for the shading, # the code needs to compute the points that, # transformed by the matrix t used to paint the shading, # produce the desired coordinates. We want coordinates # that are transformed as follows: # # P' = P x t # # where P' is the point in untransformed user space that # we want as the origin, P is the point in transformed # user space that will be transformed by t, the matrix # which transforms the circles into rotated ellipses. # # So we want to calculate P such that P' = P x t . # # Notice that if P = P' x Inverse(t) then: # # P' = P' x Inverse(t) x t = P' x Identity = P'. # # This means that we can calculate the point P # by computing P' x Inverse(t). inverseT = Quartz.CGAffineTransformInvert(t) # Now the code can transform the coordinates through the # inverse transform to compute the new coordinates. These # coordinates, when transformed with the transform t, # produce the original coordinate. circleACenter = Quartz.CGPointApplyAffineTransform(circleACenter, inverseT) circleBCenter = Quartz.CGPointApplyAffineTransform(circleBCenter, inverseT) shading = Quartz.CGShadingCreateRadial( Utilities.getTheCalibratedRGBColorSpace(), circleACenter, circleARadius, circleBCenter, circleBRadius, redBlackFunction, extendStart, extendEnd) # The code is finished with the function so release it. del redBlackFunction if shading is None: print("Couldn't create the shading!") return # Transform coordinates for the drawing of the shading. # This transform produces the rotated elliptical shading. Quartz.CGContextConcatCTM(context, t) Quartz.CGContextDrawShading(context, shading)