def doRotatedEllipses(context): totreps = 144 tint = 1.0 tintIncrement = 1.0 / totreps # Create a new transform consisting of a 45 degrees rotation. theTransform = Quartz.CGAffineTransformMakeRotation(math.pi / 4) # Apply a scale to the transform just created. theTransform = Quartz.CGAffineTransformScale(theTransform, 1, 2) # Place the first ellipse at a good location. Quartz.CGContextTranslateCTM(context, 100.0, 100.0) for _ in range(totreps): # Make a snapshot the coordinate system. Quartz.CGContextSaveGState(context) # Set up the coordinate system for the rotated ellipse. Quartz.CGContextConcatCTM(context, theTransform) Quartz.CGContextBeginPath(context) Quartz.CGContextAddArc(context, 0.0, 0.0, 45.0, 0.0, 2 * math.pi, 0) # Set the fill color for this instance of the ellipse. Quartz.CGContextSetRGBFillColor(context, tint, 0.0, 0.0, 1.0) Quartz.CGContextDrawPath(context, Quartz.kCGPathFill) # Restore the coordinate system to that of the snapshot. Quartz.CGContextRestoreGState(context) # Compute the next tint color. tint -= tintIncrement # Move over by 1 unit in x for the next ellipse. Quartz.CGContextTranslateCTM(context, 1.0, 0.0)
def doRotatedEllipsesWithCGPath(context): totreps = 144 tint = 1.0 tintIncrement = 1.0 / totreps # Create a new transform consisting of a 45 degree rotation. theTransform = Quartz.CGAffineTransformMakeRotation(math.pi / 4) # Apply a scaling transformation to the transform just created. theTransform = Quartz.CGAffineTransformScale(theTransform, 1, 2) # Create a mutable CGPath object. path = Quartz.CGPathCreateMutable() if path is None: print("Couldn't create path!") return # Add a circular arc to the CGPath object, transformed # by an affine transform. Quartz.CGPathAddArc(path, theTransform, 0.0, 0.0, 45.0, 0.0, 2 * math.pi, False) # Close the CGPath object. Quartz.CGPathCloseSubpath(path) # Place the first ellipse at a good location. Quartz.CGContextTranslateCTM(context, 100, 100) for _ in range(totreps): Quartz.CGContextBeginPath(context) # Add the CGPath object to the current path in the context. Quartz.CGContextAddPath(context, path) # Set the fill color for this instance of the ellipse. Quartz.CGContextSetRGBFillColor(context, tint, 0.0, 0.0, 1.0) # Filling the path implicitly closes it. Quartz.CGContextFillPath(context) # Compute the next tint color. tint -= tintIncrement # Move over for the next ellipse. Quartz.CGContextTranslateCTM(context, 1, 0.0)
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 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 doPatternMatrix(context): basePatternMatrix = Quartz.CGAffineTransformMakeScale(20, 20) pattern = createRedBlackCheckerBoardPattern(basePatternMatrix) if pattern is None: print("Couldn't create pattern!") return # Create the pattern color space. Since the pattern # itself has intrinsic color, the 'baseColorSpace' parameter # to Quartz.CGColorSpaceCreatePattern must be None. patternColorSpace = Quartz.CGColorSpaceCreatePattern(None) Quartz.CGContextSetFillColorSpace(context, patternColorSpace) del patternColorSpace Quartz.CGContextTranslateCTM(context, 40, 40) Quartz.CGContextSetPatternPhase(context, scalePatternPhase(Quartz.CGSize(40, 40))) # The pattern has intrinsic color so the color components array # passed to Quartz.CGContextSetFillPattern is the alpha value used # to composite the pattern cell. # Paint the pattern first with alpha = 1. color = [1] Quartz.CGContextSetFillPattern(context, pattern, color) # Rectangle 1. Quartz.CGContextFillRect(context, Quartz.CGRectMake(0, 0, 100, 100)) Quartz.CGContextSaveGState(context) if 1: # Rectangle 2. # Paint the pattern with 65% alpha. color = [0.65] Quartz.CGContextSetFillPattern(context, pattern, color) # Rotate 45 degrees about the point (150, 50). Quartz.CGContextTranslateCTM(context, 150.0, 50.0) Quartz.CGContextRotateCTM(context, Utilities.DEGREES_TO_RADIANS(45.0)) Quartz.CGContextTranslateCTM(context, -50.0, -50.0) # Rectangle 2. Patterns do not translate, scale or # rotate with the CTM. You can see that the pattern # tile of this filled rectangle is that of Rectangle # 1. Quartz.CGContextFillRect(context, Quartz.CGRectMake(0, 0, 100, 100)) # Release the pattern. del pattern Quartz.CGContextRestoreGState(context) Quartz.CGContextSaveGState(context) if 1: # Rectangle 3. The pattern is rotated with the object. # Rotate 45 degrees about the point 250, 50. t = Quartz.CGAffineTransformMakeTranslation(250.0, 50.0) t = Quartz.CGAffineTransformRotate(t, Utilities.DEGREES_TO_RADIANS(45.0)) # Translate back to -50, -50. t = Quartz.CGAffineTransformTranslate(t, -50.0, -50.0) Quartz.CGContextConcatCTM(context, t) # Make a new pattern that is equivalent to # the old pattern but transformed to current user # space. The order of transformations is crucial. # This ordering is equivalent to using the same pattern # matrix as before but transforming base space by t. patTransform = Quartz.CGAffineTransformConcat(basePatternMatrix, t) pattern = createRedBlackCheckerBoardPattern(patTransform) color = [1] Quartz.CGContextSetFillPattern(context, pattern, color) # Release the pattern. del pattern Quartz.CGContextFillRect(context, Quartz.CGRectMake(0, 0, 100, 100)) Quartz.CGContextRestoreGState(context) Quartz.CGContextSaveGState(context) if 1: # Rectangle 4. The pattern is scaled with the object. # Translate and scale. t = Quartz.CGAffineTransformMakeTranslation(320, 0) t = Quartz.CGAffineTransformScale(t, 2, 2) Quartz.CGContextConcatCTM(context, t) # Make a new pattern that is equivalent to # the old pattern but transformed to current user # space. The order of transformations is crucial. # This ordering is equivalent to using the same pattern # matrix as before but transforming base space by t. patTransform = Quartz.CGAffineTransformConcat(basePatternMatrix, t) pattern = createRedBlackCheckerBoardPattern(patTransform) color = [1] Quartz.CGContextSetFillPattern(context, pattern, color) # Release the pattern. del pattern Quartz.CGContextFillRect(context, Quartz.CGRectMake(0, 0, 100, 100)) Quartz.CGContextRestoreGState(context)
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)