代写代考 IAT 265 Week 3

IAT 265 Week 3
Transformations and Vectors
______________________________________________________________________________________
SCHOOL OF INTERACTIVE ARTS + TECHNOLOGY [SIAT] | WWW.SIAT.SFU.CA

Copyright By PowCoder代写 加微信 powcoder

 Transformation: Translation, Rotation, Scale (in Java) – Graphics2D for transformation
– Case study: translate, rotate, scale a ladybug
 AffineTransform
– Velocity operations for moving and chasing
– PVector (from Processing) for implementation – Case study: Ladybug approaches a Seed
1/23/2022 IAT 265 2

Graphics2D
 Graphics2D class is a newer version drawing tool than Graphics class
 It is a subclass of Graphics but is more powerful in the sense that:
– It draws or fills primitives in a more flexible way
– It can draw more primitives than its parent class, e.g.
(These two topics will be covered next week)
– It provides transformation functionalities (translate, rotate, scale etc.)
– It can draw with better quality (anti-aliasing)
1/23/2022 IAT 265 3

Transformation
 Translation
– Is about shifting the drawing space to a new location
– For graphics programming, this means moving the origin (0, 0) to a different location in our window
 Rotation
– Is about rotating the drawing space around its origin by
– Is about increasing/decreasing the objects’ appearances
by stretching/shrinking the drawing space
1/23/2022 IAT 265 4

Translation
 Translation gives us another way of drawing at a new location
 Before that, let’s examine drawing directly in the
default drawing space:
default origin of the screen
paintComponent(Graphics g){
//create an instance of
Graphics2D by type casting
Graphics2D g2 = (Graphics2D) g;
g2.fillRect(10, 10, 50, 50);
1/23/2022 IAT 265

Translation
 Now call translate(), any drawing done thereafter will treat the location translated to as
the new origin (0, 0)
//To draw the rect using the same
coordinates after translation
g2.translate( 10, 10 );
g2.fillRect(10, 10, 50, 50);
1/23/2022 IAT 265

Translation (2)
 What if we want to, after the call to translate(10, 10), draw at the same location as before the translation?
//To draw the rect at the same //location as before g2.translate( 10, 10 ); g2.fillRect(0, 0, 50, 50);
 Making use of new (0, 0) to specify the location of
shapes is what we should do
1/23/2022 IAT 265

 Much like Translation, rotation rotates the drawing space, so that we can draw at different orientation
 Most of the time, you’ll want to use rotation in conjunction with translation
– Otherwise rotate()rotates around the top- left corner of the screen – the default origin
• This won’t be what you want in most cases!! 1/23/2022 IAT 265 8

 Let’s use translation before rotation  Where should we translate to?
– The point around which we want to rotate • So let’s try and rotate around the center of the
• This means shifting the origin to somewhere on the screen, and drawing the square around it
1/23/2022 IAT 265 9

 Let’s start with setting our rotation point: (0, 0)
g2.translate(100, 100);
1/23/2022 IAT 265
(100, 100)

 To draw a square with the new origin being its center, we need:
g2.fillRect(-25, -25, 50, 50);
1/23/2022 IAT 265
(-25, -25)

 Now let’s rotate the drawing space after translate:
g2.translate(100, 100);
double angle = Math.PI/4;
g2.rotate(angle);

 Then we draw the same square as before, it will have the same center point but rotated
double angle = Math.PI/4; g2.rotate(angle);
g2.fillRect( -25, -25, 50, 50);
g2.translate(100, 100);
1/23/2022 IAT 265 13

Try and see the effect …
float angle = 0;
public void paintComponent(Graphics g) {
super.paintComponent(g); //Call JPanel’s method to clear
Graphics2D g2 = (Graphics2D) g;
g2.translate(100, 100);
the background
g2.rotate(angle);
g2.setColor(new Color(255, 128, 0));
g2.fillRect (-25, -25, 50, 50); }
public void actionPerformed(ActionEvent e) { angle += 0.01;
repaint();
1/23/2022 IAT 265 14 }

Improving Rendering Quality
 From the previous example, you might have noticed that the quality of rendering is pretty poor, with jags along the edges
 Graphics2D has a method that would allow us to improve the rendering quality
– setRenderingHint(RenderingHints.KeyhintKey,ObjecthintValue)
 RenderingHints.Key is a nested class, which has many static constants, among them, the following key-values work in pair to turn it on/off, removing jags along the edges of shapes:
– KEY_ANTIALIASING
– VALUE_ANTIALIAS_ON or VALUE_ANTIALIAS_OFF
1/23/2022 IAT 265 15

Rotation of Figures
 Figure consists of complex shapes, which you may need to rotate it as a whole or part of it (micro-animations)
 For rotating the whole figure:
– Translate to the rotation point, and then draw each of its body parts w.r.t. this new (0,0)
• Snowman: rocking vs swinging from thread
 For rotating a body part, translate to where the joint point is supposed to be, draw the part w.r.t. it
– E.g. make wings flap around its joint point with the body

Summary on
Translation and Rotation
 Translation moves the drawing space to a specified location
– The location that was translated to represents the new origin (0, 0)
 Rotation is about rotating the drawing space around its (desirably translated) origin by an angle
 For most cases, you should do rotation in conjunction with translation, to make your shape or figure rotate around a point that is desirable to the visual effect
1/23/2022 IAT 265 17

Case study: translate & rotate a Ladybug object
 We’ll design and animate a Ladybug object by way of translate and rotate methods of Graphics2D
1/23/2022 IAT 265 18

Draw the ladybug with translate
 Step 1: translate to (bugX, bugY) which will be used as
the center of the bug’s body, and then draw all shapes
around the new (0, 0) (0, 0)
translate (bugX, bugY)
body: fillOval(-bodyW/2, -bodyH/2, bodyW, bodyH); dot 1: fillOval(10, -12, 7, 7);
head: fillArc(bodyW / 2-6, -6, 12, 12, -90, 180);
antenna 1: drawArc(11, 0, bodyW/2, bodyH/2, 0, 90);
body line: drawLine(-bodyW / 2, 0, bodyW / 2, 0);
IAT 265 19

Move the ladybug
 Step 2: create a move() method to move the bug by speedX
void move() {
} bugX = bugX + speedX
Since paintComponent() will call drawBug() and thereby g2.translate(bugX, bugY) with each timer tick, this is actually moving forward the origin of the drawing space
IAT 265 20

Right Edge Detection
 Step 3: Right edge detection*
In move() method, make the bug reverse its movement when its antenna hit the right edge:
if((bugX + bodyW / 2 + bodyW / 4) > (BugPanel.GARDEN_X + BugPanel.GARDEN_W)) {
speedX = -speedX;
Right edge of garden
Front end of ladybug
* Please note: translation is about shifting drawing space for display
only, when it comes down to collision detection always use the default
coordinate system
1/23/2022 IAT 265 21

Rotate the ladybug when moving backward
 Step 4: make the bug rotate when reversing
//Make it rotate by 180 degree around its center
If( speedX < 0) { g2.rotate(Math.PI); } IAT 265 22 Left Edge Detection  Step 5: Left Edge detection Make the bug reverse its movement again when hitting left side of garden: if((bugX - bodyW / 2 - bodyW / 4) < BugPanel.GARDEN_X)) { speedX = -speedX ; We can use || to create compound if-statement: if((bugX+bodyW/2+bodyW/4) > (BugPanel.GARDEN_X + BugPanel.GARDEN_W) || (bugX-bodyW/2-bodyW/4) < BugPanel.GARDEN_X) { speedX = -speedX; IAT 265 23 Last step : rotate again?  After it hits the left edge of the garden IAT 265 24 As speedX is now positive, (speedX < 0) evaluates to false, so rotate(Math.PI) won’t be executed, it restores to default orientation (angle= 0) . Therefore you don’t actually need to do anything in this case.  Graphics2D object has one method for scaling that is defined as follows  scale(double sx, double sy) – sx: percentage to scale along x dimension – sy: percentage to scale along y dimension – e.g. g2.scale(2.0, 0.5) scales the objects up to 200% along x, and down to 50% along y respectively  This is done by scaling the drawing space by the factors – may cause tricky issue for objects’ collision detections (which involves the original coordinate system only) 1/23/2022 IAT 265 25 Scale the ladybug  Scale the bug by a scale factor of 2.0 double scale = 2.0; //Scale the bug’s view by scale g2.scale(scale, scale);  Two possibilities: – Scale both the bug and the garden with the same factor (no boundary detection issue in this case) – Scale the bug only NOT the garden (need to adjust boundary detection conditionals with the scale factor) • In doing all our assignments and projects, we would like to apply scale to the objects ONLY not including the background 1/23/2022 IAT 265 26 Update the Design to include Attribute for Scale  Add to Ladybug class a field of scale, and a parameter to its constructor for initialization 1/23/2022 IAT 265 27 Use the scale field to scale the bug only  Call scale() after translating the bug rect(GARDEN_X, GARDEN_Y, GARDEN_W, GARDEN_H); //draw bug fill(160, 0, 0); translate(bugX, bugY); //scale the bug’s size by scale g2.scale(scale, scale); IAT 265 28 Tricky issue with boundary detection  Appearance is now enlarged but boundary detection is still based on the original size if(bugX+(bugW/2+bugW/4) > Garden_X+Garden_W)
1/23/2022 IAT 265 29

To Fix …
 Multiply the bug’s total width with the scale factor accordingly
IAT 265 30
if(bugX+ (bodyW / 2 + bodyW / 4)*scale > GARDEN_X+GARDEN_W) We need to do the same to the other side, so to compound them, we get:
if(bugX+ (bodyW / 2 + bodyW / 4)*scale > GARDEN_X+GARDEN_W || bugX – (bodyW / 2 + bodyW / 4)*scale < GARDEN_X ) To make the bug start properly after scaling, we need to offset its initial location in BugPanel as well: bug = new Ladybug((int) (GARDEN_X + 50 * scale), ... ); How to deal with the upside- down issue after rotation? 1/23/2022 IAT 265 To resolve: flip the drawing space along x scale(-1, 1) 1/23/2022 IAT 265 scale(-1, 1) to flip the drawing space along x If( changeX < 0) { g2.scale(-1, 1); with Multiple Transformations  Transformations (including translations, rotations & scaling) are cumulative – This means when multiple transformations are done for different shapes (e.g. animal and food), the transformation done for one shape would affect those after it, which would result in unexpected results 1/23/2022 IAT 265 34 Ex: How to create a figure like this? 1/23/2022 IAT 265 35 Ex: How to create a figure like this?  Just do the followings? g2.translate(200, 200); g2.fillOval(-25, -25, 50, 50); g2.translate(-75, -75); g2.rotate(-Math.P I / 4 ) ; g2.fillRect(-15, -25, 30, 50); g2.translate(75, -75); g2.rotate(Math.P I / 4 ) ; g2.fillRect(-15, -25, 30, 50); (-75, -75) (200, 200) However the result is ... – g2.translate(200,200); – g2.translate(-75,-75); g2.rotate(-Math.PI/4); – g2.translate(75,-75); g2.rotate(Math.PI/4);  This is because transformation is cumulative  (x”~y”) is based on (x’~y’), rather than (x~y) 1/23/2022 IAT 265 (200, 200) Solution: save & restore transform attributes for transformations  In Java, all transformations are associated with transform attributes (regarding its location, orientation, scaling etc.), can be stored in an instance of the AffineTransform class  What we need here is to: 1. Save the transform attributes before we do transformations for a shape 2. Do transformations for the shape and then its rendering 3. Restore the transform attributes to what it once was after the rendering  We can then transform and render another shape, so that it will start from the same transform attributes 1/23/2022 IAT 265 38 Implementation with AffineTransform  PseudocodeProgrammingProcess(PPP): 1. We call Graphics2D’s getTransform() method to retrieve the current transform attributes and save it into an AffineTransform instance before we do transformations for a shape 2. When finished transforming and drawing for the shape, we call Graphics2D’s setTransform(AffineTransform tx) and set it back to the saved AffineTransform instance to restore the previous state of the transform attributes 3. Do so for each of the rest shapes that needs its own transformation* - except for the last shape involved IAT 265 39 Implement per the PPP g2.translate(200, 200); g2.fillOval(-25, -25, 50, 50); AffineTransform transform = g2.getTransform(); //save(x~y) g2.translate(-75, -75); g2.rotate(-Math.P I / 4 ) ; g2.fillRect(-15, -25, 30, 50); g2.setTransform(transform); //restore(x~y) g2.translate(75, -75); g2.rotate(Math.P I / 4 ) ; g2.fillRect(-15, -25, 30, 50); (-75, -75) (200, 200) 14/023/2022 IAT 265 (200, 200) x (200, 200) Summary on Transformations  Each time you translate, rotate or scale, it's referred to as a transformation  When different transformations for multiple shapes are involved, you should call getTransform() to save the transform attributes before each transformation, render your shape, and then call setTransform(AffineTransform tx) to return to the previous transform attributes – Except for the last one. But to make thing easier, even if you include it, it won’t hurt much overhead-wise  Make sure that each call to getTransform() has a matching call to setTransform(AffineTransform tx) – Nest getTransform() and setTransform(AffineTransform tx) when it’s necessary 1/23/2022 IAT 265 41 How to move toward a Target?  Need a velocity with direction toward the target location  Better to use vectors to model – Location – Velocity 1/23/2022 IAT 265 42  What is a vector  Vectors for motion – Location – Velocity – Acceleration IAT 265 43 What is a vector?  Euclidian vector: An entity that has both magnitude and direction  In motion: 1/23/2022 IAT 265 44 Vector operations  Add – allow for displacement – location+velocitynew_location  Subtract – allow for targeted motion – target_location - source_location  path vector – allowing to move toward a target  Magnitude – the length" of the vector – Magnitude of the path vector is the distance between source location and target 1/23/2022 IAT 265 45 from Processing core library  Constructor: PVector(float x, float y)  Make an object move PVector location = new PVector(50.0,100.0) PVector velocity = new PVector(3.0,-1.0) ...location.add(velocity) //updates location vector 1/23/2022 IAT 265 46 Subtraction – path to move PVector path = targetPos.sub(fishPos); //WRONG //because non-static sub(PVector p) returns void PVector path = PVector.sub(targetPos, fishPos); //RIGHT //static sub(PVector p1, PVector p2) returns a PVector object 1/23/2022 IAT 265 47 Path to Move: get Angle and Distance float angle = Math.atan2(path.y, path.x)  PVector provides a shortcut: float angle = path.heading();  To calculate distance of path: float distance = path.mag(); IAT 265 48 Path to Move: set vel  static PVector fromAngle (float angle) – Returns a new unit vector (i.e. length =1) from the IAT 265 49 specified angle //create a velocity toward the target PVector vel = PVector.fromAngle(angle); vel.mult(2); //beef it up  Or alternatively: PVector vel = PVector.sub(targetPos, fishPos); vel.limit(2);  Finally move it by vel: location.add(vel); Case study: Ladybug approaches a Seed IAT 265 50 • Makes it walk randomly to hunt • Moves toward the seed once it’s • Eats it when getting close enough • Goes back to random walk Design the two Classes  Remodel Ladybug’s motion attributes with PVector  Create a method approach that would move toward a target position • positionandits getter method for getting target position in panel Codify the approach method class Ladybug { boolean approach(PVector targ) { boolean reach = false; //calculate the path to target point PVector path = PVector.sub(targ, loc); //returns the direction as angle float angle = path.heading(); //make a vel that points toward the //in BugPanel class public void actionPerformed(ActionEvent e){//move the bug //generates a seed every 10 seconds ... //If bug catches seed eat it by setting it to null repaint(); } vel = PVector.fromAngle(angle); vel.mult(2); loc.add(vel); //move toward target //check if bug reaches target if (path.mag()- bodyW/2 <= 10 ) { reach = true; return reach; } } January 23, 2022  Required – Readings in Canvas 1/23/2022 IAT 265 53 程序代写 CS代考 加微信: powcoder QQ: 1823890830 Email: powcoder@163.com