name: inverse layout: true class: center, middle, inverse --- # Introduction to Drawing Lauren Bricker CSE 340 Spring 23 --- layout: false [//]: # (Outline Slide) # Agenda - **Do this now** - Do the [❗🌡️ Warmup: Introduction to Android and Drawing on the screen](https://edstem.org/us/courses/38124/lessons/51081/slides/286280) - **Administrivia** - Please do the required readings and prep work. It will help you; it will help us help you. - Slides with the ❗ are required for lecture and section participation - Lauren's [OH](https://docs.google.com/spreadsheets/d/1RGBvFFMl4RtwUhgLLiVdtwkRhG1T0sLlqxBApW73GU4/edit?usp=sharing) (12:30-1:30) cancelled today, but she will be available in her office until 12:30. - Henry and Davin have OH today. Thevina tomorrow. - **Briefly return to our [First App](first-app.html#57)** - Starting on Drawing (for Doodle) - Animations (maybe) --- # Agenda - Do this now - Administrivia - Briefly return to our [First App](first-app.html#57) - **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 [the last slide deck](first-app.html#64) we showed 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[  ] --- # What is on your screen? .left-column50[  ] --- name: poll-everywhere # What is on your screen? .left-column[ ] ??? 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) :--: | :--:  |  ] ] ??? Get them to at least realize that the actual pixels on their screen are LEDs --- # Toolkit Support for Basic Drawing .left-column[ ] .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[ ] .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[  ] .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[  ] --- # 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   [Source: Wikipedia](https://en.wikipedia.org/wiki/Analog_television#Displaying_an_image) --- # What is a component's coordinate system? .left-column[  ] .right-column[ Every view thinks `(0,0)` is at the top left of its bounding box (the minimal box that encloses that view) Including the parent view! ] --- # Drawing a line on a Canvas The `Canvas#drawLine()` method is specified using five parameters ```java // Draw the specified line using the specified paint. void drawLine(float startX, // The x-coordinate of the start point of the line float startY, // The y-coordinate of the start point of the line float stopX, // The x-coordinate of the end point of the line float stopY, // The y-coordinate of the end point of the line Paint paint) // Details on how to draw line (thickness, color) ``` The location parameters (`startX`, `startY`...) are relative to the `Canvas`'s coordinate system (with (0, 0) in the top left). --- # 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 Note that this tool has the (0, 0) coordinate in the bottom left. Bounding box vertices would be inverted in the Y-direction in most toolkits. --- # 🤔 🍐 Think, Pair: Bounding Boxes What are the coordinates for the *top left* corner of the bounding box of a line drawn on a `Canvas` that is drawn from (15, 10) to (0, 10)? Hint: draw this out on paper.... remember the (0, 0) coordinate is at the top left of the canvas. -- count: false Now go to Question 1 on the [✔️ Check your knowledge: Drawing](https://edstem.org/us/courses/38124/lessons/51081/slides/286283) slide 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 A) (0, 0)
B) (15, 10)
C) (0, 10) <--
D) (15, 15)
E) (10, 10) --- # What is a component's coordinate system? .left-column[  ] .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 2: Layout Inspector .left-column40[ This will be your best friend. Information re: [Layout Inspector vs Legacy Layout Inspector](/courses/cse340/23sp/assignments/doodle-issues/layout-inspector.html) ] .right-column60[  ] --- # What is a component's coordinate system? Assume we have our new `LineView` component. We draw a 1 pixel line on the `LineView`'s `Canvas` using the method call `drawLine(15, 0, 0, 0, p)`. At what `x`, `y` coordinate would we set the top left corner of the `LineView` so the *line* appears in the *parent view* from `(15, 10)` to `(0, 10)`? -- count: false Go to Question 2 on the [✔️ Check your knowledge](https://edstem.org/us/courses/38124/lessons/51081/slides/286283) slide to answer A) (0, 0)
B) (15, 10)
C) (0, 10)
D) (15, 15)
E) (10, 10) ??? Bring up [one note](https://uwnetid-my.sharepoint.com/personal/bricker_uw_edu/_layouts/15/Doc.aspx?sourcedoc={18b13a06-b149-4fa5-a2f4-2f9f9e2e96ec}&action=edit&wd=target%28340.one%7C381b8e1c-cd65-43bf-b176-803340c734db%2FWhat%20is%20a%20component%27s%20coordinate%20system%7C230f3888-3e92-4f9a-af11-c6f7a9abbddd%2F%29&wdorigin=NavigationUrl) Why not 15,10?
Why not 0,0 A) (0, 0)
B) (15, 10)
C) (0, 10) <--
D) (15, 15)
E) (10, 10) --- # What is a component's coordinate system? .left-column[  ] .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*? ] --- # Wait, what is the top left corner of a circle? .left-column[  ] .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, // The x-coordinate of the **center** of the circle to be drawn float cy, // The y-coordinate of the **center** of the circle to be drawn float radius, // The radius of the circle drawn Paint paint) // Details on how to draw line (thickness, color) ``` When we say *top left corner* we are really referring to the circle's bounding box's top left corner. ] --- # 🤔 🍐 Think, Pair: Bounding Box of a circle Which is a valid corner for the bounding box for a circle drawn on an Android `Canvas` using [drawCircle(100, 100, 100, p)](https://developer.android.com/reference/android/graphics/Canvas#drawCircle(float,%20float,%20float,%20android.graphics.Paint)? -- count: false Go to Question 3 on the [✔️ Check your knowledge](https://edstem.org/us/courses/38124/lessons/51081/slides/286283) slide to answer A) (0, 0)
B) (-50, -50)
C) (50, 50)
D) (-100, -100)
E) (100, 100) ??? A) (0, 0) <--
B) (-50, -50)
C) (50, 50)
D) (-100, -100)
E) (100, 100) --- # What is a component's coordinate system? .left-column[  ] .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[  ] .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[  ] .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[  ] .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? Go to Question 4 on the [✔️ Check your knowledge slide](https://edstem.org/us/courses/38124/lessons/51081/slides/286283) answer ] ??? A) (0, 0)
B) (-50, -50)
C) (50, 50)
D) (-100, -100) <--
E) (100, 100) --- ## 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[  ] --- # What is a component's coordinate system? .left-column[  ] .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[  ] .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[  ] .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[  ] .right-column[ (remember -- interactor = interactive component,
or `View`) ] --- # What does a component need to do? .left-column[  ] .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 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? Take a look at the [Doodle DrawViews](/courses/cse340/23sp/interactive/doodle_shapes.html) tool --- # 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  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[  ] .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)    --- # 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  --- 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[  ] .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