name: inverse layout: true class: center, middle, inverse --- # Introduction to Drawing Lauren Bricker CSE 340 Spring 2022 --- layout: false [//]: # (Outline Slide) # Agenda - Administrivia - Please take the time to do the required readings and prep work. It will help you; it will help us help you. - **Starting on Drawing (for Doodle)** - Abstractions for drawing on the screen - Drawing in Android - Clipping and other transformations - Animations (maybe) --- ## Developer roles .left-column[
graph LR ip[Interface Programmer] w[Component Developer] l[Library Extender] a[Architecture Extender] t[Toolkit Builder] classDef yellow font-size:14pt,text-align:center classDef green font-size:14pt,text-align:center class t,l,a yellow class ip,w green
] .right-column[ From [last class](first-app.html#57) we briefly discussed of the roles a developer can play in app development. - We played the role of an *Interface Developer* by adding existing components (`TextView` and `Button`) from the Android SDK to our cse340_aCount - Today we're *Component Developer* by thinking about how to create a new `CircleView` and `LineView` to your Doodle ] --- # Drawing on the Screen - Take out your phone. Open an App. What do you see on your screen? --- # What is on your screen? .left-column50[ ![:img Picture of a blank outer rectangle labeled "Phone Hardware" and a blank inner rectangle labeled "Operating System", 100%, width](img/drawing/bounding1.png) ] --- # What is on your screen? .left-column50[ ![:img Picture of an outer rectangle labeled "Phone Hardware" and an inner rectangle labeled "Operating System". The inner rectangle has standar phone icons such as battery and time. Inside that is another blank rectangle labeled "Your App", 100%, width](img/drawing/bounding2.png) ] --- name: poll-everywhere # What is on your screen? .left-column[ ![:img Example poll everywhere mobile presenter application screen, 100%, width](img/drawing/pollevscreen.jpeg)] ??? This is what I see in poll everywhere What is an app made up of? --- template: poll-everywhere .right-column[ App is made up of? *Components* Last class we briefly discussed the "tree" of components. Think about what this hierarchy might look like. - What is at the "root" ? - How is this divided up into sections - In each section, how are things further divided up? ] --- template: poll-everywhere .right-column[
graph TD W(Window) --> T[Title Bar] W --> L[Label: My Folders] W --> F[Folders] W --> B[Toolbar] T --> TA[Icon] T --> TB[Label: Activities] T --> TC[...] F --> F1[Folder 1] F --> F2[...] F1 --> I[Icon] F1 --> N[Folder Name] F1 --> C[Activity Count] B --> H[Button:Home] B --> A[...] B --> R[Button: Reports] B --> P[Button: Profile] class W start class T,L,F,B,TA,TB,TC,F1,F2,H,A,R,P,I,N,C blue
] --- template: poll-everywhere .right-column[ App is made up of? Components What are components made up of? ] ??? Should push them down to the lowest level on the screen App is made up of? Components Components are made up of? lines, circles, text Lines, circles and text are made up of? Pixels --- template: poll-everywhere .right-column[ App is made up of? Components Components are made up of? lines, circles, text Lines, circles and text are made up of? Pixels (picture elements) ] --- # Aside: Displaying a Pixel .row[ .column[ Do you know how pixels are lit up in color or greyscale? - on your computer or TV screen? - on a projector? ] ] --- # Aside: Displaying a Pixel .row[ .column[ Do you know how pixels are lit up in color or greyscale? - on your computer or TV screen? - on a projector? ] .doublecolumn[ [Cathode Ray Tube](https://en.wikipedia.org/wiki/Cathode-ray_tube) | [LED Display](https://en.wikipedia.org/wiki/LED_display) :--: | :--: ![:img Magnified view of a delta-gun shadow mask color CRT, 90%](img/drawing/CRT_display.jpg) | ![:img Detail view of a LED display with a matrix of red green and blue diodes, 90%](img/drawing/LED_display.jpg) ] ] ??? Get them to at least realize that the actual pixels on their screen are LEDs --- # Toolkit Support for Basic Drawing .left-column[ ![:img Example poll everywhere mobile presenter application screen, 85%, width](img/drawing/DrawingPanel.png)] .right-column[ All toolkits have some sort of `Canvas` object or abstraction - `Canvas` is an object level abstraction for performing drawing operations - Each *Component* (`View`) has a `Canvas` in Android - You can access it in the `onDraw(Canvas canvas)` method *Aside: Components Widgets, Interactors, and `Views` are all variations on the same term* ] .footnote[See [David Novik](https://twitter.com/NovickProf) on Twitter] ??? Connect to DrawingPanel in 143? In Android, we call these components `Views` --- # Toolkit Support for Basic Drawing .left-column[ ![:img Example poll everywhere mobile presenter application screen, 85%, width](img/drawing/DrawingPanel.png)] .right-column[ When is `onDraw()` called? - Handled automatically for you by toolkit - Triggered whenever the pixels are *dirty* (there's been a change to what needs to be viewed) - You can trigger this with `invalidate()` (we'll use this in the future) ] .footnote[See [David Novik](https://twitter.com/NovickProf) on Twitter] ??? Lots to discuss here. Mainly focus on introducing the concept of a library (a bunch of components you can pick from, Canvas and its methods, etc) vs an architecture (which controls when and in what order things happen). We'll learn about both in this class. You need to understand both to use a toolkit. --- # How does Canvas work? - Drawing is done by calling methods for different kinds of objects -- count: false - For example: `drawRect`, `drawOval`, `drawLine`, `drawPath` ... [Full List in the API Documentation](https://developer.android.com/reference/android/graphics/Canvas.html) --- # What is on your screen, Doodle Edition .row[ .column[ ![:img Picture of the same phone with Phone Hardware and Operating System. Inside the your app box Part 2B of the doodle app is visible with many circles and lines and the words "Test Page". Examples are labeled as LineView and CircleView and TextView and DrawView, 100%, width](img/drawing/bounding3.png) ] .doublecolumn[
graph TD Part1B(Part1ActivityB) --> C1[Circle1] Part1B --> C2[Circle2] Part1B --> Cd[...] Part1B --> C9[Circle9] Part1B --> Text[Test Page] Part1B --> I1[Image1] Part1B --> Id[...] Part1B --> I4[Image4] Part1B --> L1[Line1] Part1B --> Ld[...] Part1B --> L4[Line8] class Part1B start class C1,C2,Cd,C9,Text,I1,Id,I4,L1,Ld,L4 blue
] ] --- # What is a component's coordinate system? .left-column[ ![:img This shows the same Part2B but each component has its bounding box visible. The top left corner of the whole app is labeled as 0 0 and the bounding boxes of components extend outside the pp, 100%, width](img/drawing/bounding4.png) ] --- # The standard coordinate system - (0,0) is at the top left of the screen - The screen is drawn pixel by pixel from top left to bottom right in "raster" lines ![:img Picture of a very old CRT based TV display, 25% width](img/drawing/analogtv.jpg) ![:img Picture of raster scanning going from top left to top right; down a row; and so on, 35%, width](img/drawing/rasterscanning.png) [Source: Wikipedia](https://en.wikipedia.org/wiki/Analog_television#Displaying_an_image) --- # What is a component's coordinate system? .left-column[ ![:img Now each bounding box is also labeled with a 0 0, 100%, width](img/drawing/bounding5.png) ] .right-column[ Every view thinks `(0,0)` is at the top left of its bounding box (the minimal box that encloses that view) Doodle has lots of views! ] --- # Aside 1: Bounding box of an object A bounding box (or sometimes [Minimum Bounding Box](https://en.wikipedia.org/wiki/Minimum_bounding_box)) is a term used in coordinate geometry to describe the smallest rectangular area that contains an object or set of objects. Great example to play with: https://www.mathopenref.com/coordbounds.html --- # Aside 2: Layout Inspector .left-column40[ This will be your best friend. Information re:[Layout Inspector vs Legacy Layout Inspector](/courses/cse340/22sp/assignments/doodle-issues/layout-inspector.html) ] .right-column60[ ![:img A screen capture of the layout inspector with lables for how to start it and the components, 100%, width](img/drawing/layout_inspector.png) ] --- # 🤔 🍐 Think, Pair: Bounding Boxes What are the coordinates for the top left corner of the bounding box of a `RIGHTLEFT` line in a `LineView` that goes from (15, 10) to (0, 10)? -- **Hint** : we should have said "relative to the parent `View`." --- # 🤔 🍐 Think, Pair: Bounding Boxes What are the coordinates for the top left corner of the bounding box of a `RIGHTLEFT` line in a `LineView` that goes from (15, 10) to (0, 10)? Go to the Drawing Quiz [Ed lesson](https://edstem.org/us/courses/21053/lessons/31152/slides/180442) for today to check your answer A) (0, 0)
B) (15, 10)
C) (0, 10)
D) (15, 15)
E) (10, 10) ??? Why not 15,10?
Why not 0,0 ( ) (0, 0)
( ) (15, 10)
(X) (0, 10)
( ) (15, 15)
( ) (10, 10) --- # What is a component's coordinate system? .left-column[ ![:img The top left circle is highlighted. Only a quarter of it is inside the window, 100%, width](img/drawing/bounding5.5.png) ] .right-column[ If the radius of the top left `CircleView` is 100 pixels - What are the coordinates of the circle's top left corner *in its parent coordinates*? ] --- # What is the top left corner of a circle? .left-column[ ![:img The center and bounding box of the top left circle are highlighted, 100%, width](img/drawing/bounding6.png) ] .right-column[ Android's [Canvas](https://developer.android.com/reference/android/graphics/Canvas) `drawCircle()` is specified using center x, center y and radius ```java // Draw the specified circle using the specified paint. void drawCircle(float cx, float cy, float radius, Paint paint) ``` When we say *top left corner* we are really referring to the circle's bounding box's top left corner. ] --- # 🤔 🍐 Think, Pair: Bounding Boxes Which is a valid corner for a bounding box for a circle drawn using the Android Canvas to [drawCircle(10, 10, 10, p)](https://developer.android.com/reference/android/graphics/Canvas#drawCircle(float,%20float,%20float,%20android.graphics.Paint)? Go to the Drawing Quiz [Ed lesson](https://edstem.org/us/courses/21053/lessons/31152/slides/180442) for today to check your answer ( ) (10, 10)
( ) (10, 20)
( ) (0, 0)
( ) (20, 10) ??? ( ) (10, 10)
( ) (10, 20)
(X) (0, 0)
( ) (20, 10) --- # What is a component's coordinate system? .left-column[ ![:img Now each bounding box is also labeled with a 0 0, 100%, width](img/drawing/bounding7.png) ] .right-column[ Now let's assume each thing that is drawn is in its own Component (a [View](https://developer.android.com/reference/android/view/View)) If the radius of the top left CircleView is 100 pixels... ] --- # What is a component's coordinate system? .left-column[ ![:img Now each bounding box is also labeled with a 0 0, 100%, width](img/drawing/bounding7.png) ] .right-column[ Now let's assume each thing that is drawn is in its own Component (a [View](https://developer.android.com/reference/android/view/View)) If the radius of the top left `CircleView` is 100 pixels... - What are the coordinates of the circle's top left corner? ] --- # What is a component's coordinate system? .left-column[ ![:img Now each bounding box is also labeled with a 0 0, 100%, width](img/drawing/bounding7.png) ] .right-column[ Now let's assume each thing that is drawn is in its own Component (a [View](https://developer.android.com/reference/android/view/View)) If the radius of the top left CircleView is 100 pixels... - What are the coordinates of the circle's top left corner? Oops, that's a trick question... in which coordinate system? ] --- # What is a component's coordinate system? .left-column[ ![:img The center and bounding box of the top left circle are highlighted, 100%, width](img/drawing/bounding7.png) ] .right-column[ Now let's assume each thing that is drawn is in its own Component (a [View](https://developer.android.com/reference/android/view/View)) If the radius of the top left CircleView is 100 pixels... - What are the coordinates of the circle's top left corner *in its parent coordinates*? - What is the CircleView's parent? ] --- ## Aside 3: How do you place a child window in a parent [View](https://developer.android.com/reference/android/view/View)? `View#setX(float)` and `View#setY(float)` to set a child's x and y position **in pixels** relative to the parent view's origin (0, 0) `View#setMinimumWidth(float)` and `View#setMinimumHeight(float)` set the minimum width and height of the bounding box, **in pixels**. We will be discussing why we talk about minimum width and height when we discuss layout. **Note** : The notation above, ClassName#methodName(
), is a common way to describe a specific method in a specific class --- ## Aside 3: Pause... What is the difference between `View#setX(float)` and `View#setY(float)` and `View#setLeft(float)` and `View#setTop(float)` Open the [View](https://developer.android.com/reference/android/view/View) documentation and find out. -- count: false - `View#setX(float)` and `View#setY(float)` set the exact location relative to the screen - `View#setLeft(float)` and `View#setTop(float)` set the location relative to the parent More information on [Stack Overflow](https://stackoverflow.com/questions/28903623/setx-settranslationx-setleft-layoutparam-leftmargin-matrix-whats-the-diff) --- # Aside 4: Common Misconception .left-column-half[ `View#getLeft()`/`View#getTop()` may not return the same as `View#getX()`/`View#getY()` for your window. These *may* change when the `View`s are layed out. A good description for why is also on [Stack Overflow](https://stackoverflow.com/questions/30202379/android-views-gettop-getleft-getx-gety-getwidth-getheight-meth/52810453#52810453) ] .right-column-half[ ![:img getleft and getTop returning different things from getX and getY, 100%, width](img/drawing/getlefttop-vs-getxy.png) ] --- # What is a component's coordinate system? .left-column[ ![:img Now each bounding box is also labeled with a 0 0, 100%, width](img/drawing/bounding6.png) ] .right-column[ Now let's assume each thing that is drawn is in its own Component (a [View](https://developer.android.com/reference/android/view/View)) If the radius of the top left CircleView is 100 pixels... - What are the coordinates of the circle's top left corner *in its parent coordinates*? - What are the coordinates of the circle's top left corner *in child coordinates*? ] --- # What is a component's coordinate system? .left-column[ ![:img Now each bounding box is also labeled with a 0 0, 100%, width](img/drawing/bounding6.png) ] .right-column[ Now let's assume each thing that is drawn is in its own Component (a [View](https://developer.android.com/reference/android/view/View)) If the radius of the top left CircleView is 100 pixels... - What are the coordinates of the circle's top left corner *in its parent coordinates*? - What are the coordinates of the circle's top left corner *in child coordinates*? - What is the circle's *center* in *child coordinates*? ] --- ## Aside 5: Why so many separate Components? .left-column[ ![:img Picture of an android device with 3 Views each one containing a line circle and square a different size with different backgrounds, 80%, width](img/drawing/views.png) ] .right-column[ Useful when we want to do animation Also provides **separation of concerns** and good high level control - Can have a different paint object for each view - Can easily change z-order (what is on top of what) - Can store information used to draw that thing (whatever it is) - Can either make the size of the whole screen or resize around what is drawn Views can also be re-used easily ] ??? This could be a good place to ask them to think about what that means and demonstrating two things with different z order. --- # Building an interactor from scratch .left-column[ ![:img Example poll everywhere mobile presenter application screen, 100%, width](img/drawing/pollevscreen.jpeg) ] .right-column[ (remember -- interactor = interactive component,
or `View`) ] --- # What does a component need to do? .left-column[ ![:img Example poll everywhere mobile presenter application screen, 100%, width](img/drawing/pollevscreen.jpeg) ] .right-column[ *Draw on the screen*
using [*Canvas*](https://developer.android.com/reference/android/graphics/Canvas) *Handle input*
(we won't do this until the *fourth* assignment, menus) ] --- # How do we use Canvas in Doodle? .row[ .column[
classDiagram ImageView <|-- DrawView DrawView <|-- CircleView DrawView <|-- TextView DrawView <|-- LineView DrawView <|-- MyView class DrawView { +getBrush() #initFromParentCoords() #onDraw() }
] .doublecolumn[ - `DrawView` can draw on screen (and be moved around). You will implement part of it. It inherits from [View](https://developer.android.com/reference/android/view/View) and can draw images. - You will implement subclasses `CircleView`, `TextView`, and `LineView` in Part 1 and and a creative `MyView` in Part 2. ] ] ??? Green: Android toolkit Blue: Classes we provide you don't have to modify Yellow: Classes you implement Remind students that they did do inheritance in 142/143 like with Critters. --- # How does Canvas work? - Drawing is done by calling methods for different kinds of objects - Lots happens under the covers... let's look at an example... -- count: false "I want to draw a line on the screen" -- count: false So I would likely call `drawLine` on the `Canvas`. -- count: false So... how do I tell the computer where the start and end of the line will be? --- # Things to think about Drawing Demo - things to think about - What is the bounding box of a line that is drawn diagonally - from upper left to lower right? - lower right to the upper left? - from the upper right to the lower left? - from the lower left to upper right? - What is bounding box of a vertical line? - What is the bounding box of a horizontal line? --- # How is a drawing object rendered on screen? - An object (like a line) would be converted into one or more **strokes** - A stroke has properties such as width or color - The stroke is converted to **pixels** (correspond to dots on your screen) - These pixels are put in a `Bitmap` (frame buffer) first, then updated on the screen all at once ??? top left is from old-style raster graphics, where a beam of light literally moved down the screen from top left to bottom right, causing chemical excitation when on and thus lighting the screen the last is left over from when both graphics and drawing were slower and more linear Still most reliable approach --- # How is a stroke converted to pixels? - Strokes (can be) size independent. Pixels are not - Strokes are continuous. Pixels are not - Anti-aliasing Essentially converting from **vector** to **raster** graphics ([Bresenham's algorithm](https://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm)) --- # Quick understanding test What internal data structure (abstraction) represents an entire picture to display on a color screen? -- pixels in a 2D array ![:img The left side of this image displays the RGB pixel values of the image of GitGrade's Hopper on the right side 3%](img/drawing/pixelcalc.png) Pixel Calculator (Tanimoto 2010) ??? **A frame buffer (2D array) (picture)** The following are wrong, they represent a single pixel (but we haven't studied this yet) - A pixel (R,G,B) - A number from 0 to 255 --- # What is the [Paint](https://developer.android.com/reference/android/graphics/Paint.html) Object? .left-column[ ![:img Picture of a phone screen with a blue and green circle drawn on it at different vertical positions (50 and 150 y center point), 100%, width](img/drawing/circles.png) ] .right-column[ A Paint object is an abstraction that determines how drawing operations should look ```java Paint drawPaint = new Paint(); drawPaint.setColor(Color.BLUE); drawPaint.setAntiAlias(true); drawPaint.setStrokeWidth(5); drawPaint.setStyle(Paint.Style.STROKE); canvas.drawCircle(500, 500, 400, drawPaint); drawPaint.setStrokeJoin(Paint.Join.ROUND); drawPaint.setStrokeCap(Paint.Cap.ROUND); drawPaint.setColor(Color.GREEN); drawPaint.setStrokeWidth(15); canvas.drawLine(350, 300, 500,600, drawPaint); ```] --- # What is the [Paint](https://developer.android.com/reference/android/graphics/Paint.html) Object? - Abstraction that determines how drawing operations should look - Drawing style: stroked, filled - Line Characteristics: color, line width, join, cap styles - Fill Characteristics (color) ![:img example dotted line--unfilled,15%, width](img/drawing/dotted.png) ![:img example solid filled,15%, width](img/drawing/filled.png) ![:img example solid unfilled,15%, width](img/drawing/unfilled.png) --- # Other Paint properties - Text Characteristics: font family, style, size, alignment settings, etc. -- count: false - Font: shapes for chars (called *glyphs*) plus layout - family or typeface ![:img examples of different types of fonts,40%, width](img/drawing/fonts.png) --- count: false # Other Paint properties - Text Characteristics: font family, style, size, alignment settings, etc. - Font: shapes for chars (called *glyphs*) plus layout - family or typeface - style: plain, *italic*, **bold**, **_both_**, ~~strikethrough~~, *etc.* -- count: false - points: 72.27 points per inch ??? because french inches were different (72 per inch) Really just a guideline these days It is the *width* of a capital M (no height specified) --- # Drawing Text .left-column-half[ Android also has methods for drawing text on a Canvas: [drawText](https://developer.android.com/reference/android/graphics/Canvas#drawText(java.lang.String,%20float,%20float,%20android.graphics.Paint) ``` canvas.drawText (String text, float x, float y, Paint paint); ``` where `x` is the location of left side of the text `y` is the location of the "baseline" of the text ] .right-column-half[ ![:img Visual of top ascent baseline descent bottom and leading in Android’s FontMetrics, 100%, width](img/drawing/fontmetrics.png) ] .footnote[From [Meaning of top, ascent, baseline, descent, bottom, and leading in Android’s FontMetrics](https://suragch.medium.com/meaning-of-top-ascent-baseline-descent-bottom-and-leading-in-androids-fontmetrics-c80cf019aef5)] --- # FontMetrics [Paint.FontMetrics](https://developer.android.com/reference/android/graphics/Paint.FontMetrics) is an object you can get from the Android `Paint` object which can give you more details about the size of the font in px units. `Paint.FontMetrics` has the following fields - `ascent` - recommended distance above baseline for singled spaced text. - 'descent`- recommended distance below baseline for singled spaced text. - `top` - maximum distance above baseline for the tallest glyph in the font at a given text size. - `bottom` - maximum distance below baseline for the lowest glyph in the font at a given text size. - `leading` - recommended additional space between lines of text. [`Paint#measureText(String)`](https://developer.android.com/reference/android/graphics/Paint#measureText(java.lang.String) will return the width the text in the current font --- # The Path Object - Canvas supports drawing primitive shapes _and_ arbitrary paths: `void drawPath(Path p, Paint paint);` -- count: false - Declaring a `Path` can be done by combining basic primitive shapes (e.g rectangles, circles, ovals, curves like arc, cubic, etc.) -- count: false - **What drawing model** does creating a path in this way correspond to? - Raster model - Vector model ??? Vector Model --- count: false # The Path Object - Canvas supports drawing primitive shapes _and_ arbitrary paths: `void drawPath(Path p, Paint paint);` - Declaring a `Path` can be done by combining basic primitive shapes (e.g rectangles, circles, ovals, curves like arc, cubic, etc.) - **Which is more scalable?** - Raster model - Vector model ??? Vector Model XXXX could do in-class [drawing exercise](https://github.com/mriveralee/ssui-mobile-exercises-2016/tree/master/exercises/lab05/CustomDrawing) IF time XXXX needs updating --- # Summary & revisiting learning goals for this week - What is on the screen: Hardware, OS, App, Components - Component Tree (Interactor Hierarchy) - Pixels (lots of dots) - Coordinate systems in parents and children - Bounding boxes - Canvas, Paint, FontMetrics, & Paths in Android - Pixel & stroke models