I need to create a new instance of my class SimpleRGB that was created in order to change the pixels of a picture to all of one color. I know I am not creating the instance correctly, but cannot figure out how to do this right.
/**
* Get the NEW image containing only the red color. The red values of this
* new image should be exactly the same as red value of this image. The
* green and blue values of this new image should be 0s.
*
* #return the NEW image (SimpleRGB) containing only the red color of this
* image.
*/
public SimpleRGB getRedImage() {
SimpleRGB redImage = new SimpleRGB(aRed);
return redImage;
}
This is the full Class
public class SimpleRGB {
private int aWidth;
private int aHeight;
private int[][] aRed;
private int[][] aBlue;
private int[][] aGreen;
public SimpleRGB(int aWidth, int aHeight) {
aRed = new int[aWidth][aHeight];
aBlue = new int[aWidth][aHeight];
aGreen = new int[aWidth][aHeight];
}
/**
* Gets the width of this image.
*
* #return the width of this image.
*/
public int getWidth() {
return aWidth;
}
/**
* Gets the height of this image.
*
* #return the height of this image.
*/
public int getHeight() {
return aHeight;
}
/**
* Sets the red value at coordinate (x,y) to aRed.
*
* #param x the x coordinate of this image.
* #param y the y coordinate of this image.
* #param aRed the red value (0 - 255)
*/
public void setRed(int x, int y, int aRed) {
this.aRed[x][y] = aRed;
}
/**
* Sets the green value at coordinate (x,y) to aGreen.
*
* #param x the x coordinate of this image.
* #param y the y coordinate of this image.
* #param aGreen the green value (0 - 255)
*/
public void setGreen(int x, int y, int aGreen) {
this.aGreen[x][y] = aGreen;
}
/**
* Sets the blue value at coordinate (x,y) to aBlue.
*
* #param x the x coordinate of this image.
* #param y the y coordinate of this image.
* #param aBlue the blue value (0 - 255)
*/
public void setBlue(int x, int y, int aBlue) {
this.aBlue[x][y] = aBlue;
}
/**
* Gets the red value at coordinate (x,y).
*
* #param x the x coordinate of this image.
* #param y the y coordinate of this image.
* #return the value of red at coordinate (x,y).
*/
public int getRed(int x, int y) {
return aRed[x][y];
}
/**
* Gets the green value at coordinate (x,y).
*
* #param x the x coordinate of this image.
* #param y the y coordinate of this image.
* #return the value of green at coordinate (x,y).
*/
public int getGreen(int x, int y) {
return aGreen[x][y];
}
/**
* Gets the blue value at coordinate (x,y).
*
* #param x the x coordinate of this image.
* #param y the y coordinate of this image.
* #return the value of blue at coordinate (x,y).
*/
public int getBlue(int x, int y) {
return aBlue[x][y];
}
/**
* Get the NEW image containing only the red color. The red values of this
* new image should be exactly the same as red value of this image. The
* green and blue values of this new image should be 0s.
*
* #return the NEW image (SimpleRGB) containing only the red color of this
* image.
*/
public SimpleRGB getRedImage() {
SimpleRGB redImage = new SimpleRGB(aWidth,aHeight);
return redImage;
}
/**
* Get the NEW image containing only the green color. The green values of
* this new image should be exactly the same as green value of this image.
* The red and blue values of this new image should be 0s.
*
* #return the NEW image (SimpleRGB) containing only the green color of this
* image.
*/
public SimpleRGB getGreenImage() {
SimpleRGB greenImage = new SimpleRGB(aWidth,aHeight);
return greenImage;
}
/**
* Get the NEW image containing only the blue color. The blue values of this
* new image should be exactly the same as blue value of this image. The red
* and green values of this new image should be 0s.
*
* #return the NEW image (SimpleRGB) containing only the blue color of this
* image.
*/
public SimpleRGB getBlueImage() {
SimpleRGB blueImage = new SimpleRGB(aWidth,aHeight);
return blueImage;
}
/**
* Get the NEW image representing the greyscale of this image. The grey
* colors are colors that the red, green and blue value are exactly the
* same. To convert an RGB image into a greyscale image, use the following
* formula to calculate the new value. (0.21 * red) + (0.72 * green) + (0.07
* * blue) For example, suppose the (R,G,B) value of this image at
* coordinate (10,20) are (10,100,200), since (0.21 * 10) + (0.72 * 100) +
* (0.07 * 200) = 88 the (R,G,B) value of the new greyscale image at (10,20)
* should be (88,88,88).
*
* #return the NEW image representing the greyscale of this image.
*/
public SimpleRGB getGreyImage() {
SimpleRGB greyImage = new SimpleRGB(aWidth,aHeight);
return greyImage;
}
}
I would do:
public SimpleRGB getRedImage() {
SimpleRGB result = new SimpleRGB(aWidth,aHeight);
for (int x = 0; x < aWidth; x++) {
for (int y = 0; y < aHeight; y++) {
result.setRed(x, y, this.getRed(x, y));
}
}
return result;
}
This creates a new SimpleRGB image with all color values set to 0 (by default all values in an int array are initialized to 0). Then it sets the red value of this new SimpleRGB to match the current RGB's red values at each point in the current RGB.
public SimpleRGB getRedImage() {
SimpleRGB redImage = new SimpleRGB(aWidth, aHeight);
for (int x = 0; x < aWidth; ++x) {
System.arraycopy(aRed[x], 0, redImage.aRed[x], 0, aHeight);
}
return redImage;
}
This immediately uses private fields directly, and the low-level method System.arraycopy to do a fast copy.
Related
Create a Rectangle class that is almost identical to the Circle class. Use Rect as the class name. The easiest way to write this class will be to copy all the code from Circle.java into Rect.java, then change the class name, instance variables, and statements. My rect code only opens a blank window when I use the shapemover. Please help me identify what I am doing wrong.
Here's the circle class code:
package lab08;
import java.awt.Graphics;
import java.awt.Color;
/**
* Circle objects represent a circle shape
* drawn to the screen at a particular position
* with some size and color.
*
* #author Peter Jensen, Donat Mouele
* #version Fall 2022
*/
public class Circle extends Shape
{
// Instance variables.
private int x, y;
private Color color;
private int radius;
/**
* Constructor - initializes the position, diameter, and
* color of this circle object.
*
* #param x
* the x coordinate of this object's position
*
* #param y
* the x coordinate of this object's position
*
* #param diameter
* the diameter of this circle
*
* #param color
* the color of this circle
*/
public Circle (int x, int y, int diameter, Color color)
{
this.x = x;
this.y = y;
this.color = color;
this.radius = diameter / 2;
}
/**
* Changes the position of this shape by
* the specified amount. Note that this does
* not set the position absolutely, the deltas
* specify how far to move the shape from its
* current position.
*
* #param deltaX
* how far to move the shape horizontally
*
* #param deltaY
* how far to move the shape vertically
*/
public void move (int deltaX, int deltaY)
{
x = x + deltaX;
y = y + deltaY;
}
/**
* Draws the circle at it's current position and color
* to the specified graphics object.
*
* #param g
* the graphics object (where to draw to)
*/
public void draw (Graphics g)
{
g.setColor (color);
g.fillOval (x, y, radius * 2, radius * 2);
}
/**
* Returns true if the coordinates are within the circle.
*
* #param targetX
* an x coordinate
*
* #param targetY
* a y coordinate
*
* #return
* true if the coordinates are within the shape
*/
public boolean isInside (int targetX, int targetY)
{
int cx = x + radius; // Calculate the center point
int cy = y + radius;
int deltaX = cx - targetX; // Calculate the deltas to the click
int deltaY = cy - targetY;
// Make sure the distance from the click to the center is less
// than the radius. (Notice how I avoid a square root.)
return (deltaX * deltaX + deltaY * deltaY) <= radius * radius;
}
}
Here's the Rectangle Class Code that I have
package lab08;
import java.awt.Graphics;
import java.awt.Color;
/**
* Circle objects represent a circle shape
* drawn to the screen at a particular position
* with some size and color.
*
* #author Peter Jensen, Donat Mouele
* #version Fall 2022
*/
public class Rect extends Shape
{
// Instance variables.
private int x, y;
private Color color;
private int height;
private int width;
/**
* Constructor - initializes the position, diameter, and
* color of this circle object.
*
* #param x
* the x coordinate of this object's position
*
* #param y
* the x coordinate of this object's position
*
* #param diameter
* the diameter of this circle
*
* #param color
* the color of this circle
*/
public Rect (int x, int y, int perimeter, Color color)
{
this.x = x;
this.y = y;
this.color = color;
this.height = perimeter / 2 - width;
this.width = perimeter/2-height;
}
/**
* Changes the position of this shape by
* the specified amount. Note that this does
* not set the position absolutely, the deltas
* specify how far to move the shape from its
* current position.
*
* #param deltaX
* how far to move the shape horizontally
*
* #param deltaY
* how far to move the shape vertically
*/
public void move (int deltaX, int deltaY)
{
x = x + deltaX;
y = y + deltaY;
}
/**
* Draws the circle at it's current position and color
* to the specified graphics object.
*
* #param g
* the graphics object (where to draw to)
*/
public void draw (Graphics g)
{
g.setColor (color);
g.fillOval (x, y, width, height);
}
/**
* Returns true if the coordinates are within the circle.
*
* #param targetX
* an x coordinate
*
* #param targetY
* a y coordinate
*
* #return
* true if the coordinates are within the shape
*/
public boolean isInside (int targetX, int targetY)
{
int cx = x + width; // Calculate the center point
int cy = y + height;
int deltaX = cx - targetX; // Calculate the deltas to the click
int deltaY = cy - targetY;
return targetX >= x &&
targetX < x + width &&
targetY >= y &&
targetY < y + height;
}
}
Here's the shape mover
package lab08;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
/**
* This class represents and application/JPanel that
* draws a few shapes for the user and allows the
* user to drag the shapes around with the mouse.
*
* #author Peter Jensen
* #version Fall 2022
*/
public class ShapeMover extends JPanel implements MouseListener,
MouseMotionListener,
Runnable
{
// Instance variables.
Rect[] shapes;
int lastX, lastY;
Rect current;
/**
* Initialize this (our JPanel). Create the shapes, and
* register this object as a listener to mouse events
* produced by this object.
*/
public ShapeMover ()
{
// Make the shapes.
shapes = new Rect[]
{
new Rect (130, 40, 60, Color.RED),
new Rect (230, 40, 20, Color.BLUE),
new Rect (330, 40, 80, Color.GREEN.darker()),
new Rect (130, 140, 100, new Color (0.8f, 0.6f, 0.2f)),
new Rect ( 30, 140, 40, Color.YELLOW)
};
// Set the size of this panel.
Dimension d = new Dimension (600, 600);
this.setMinimumSize(d);
this.setPreferredSize(d);
this.setMaximumSize(d);
// Register this object as a listener to its own events.
this.addMouseListener (this);
this.addMouseMotionListener (this);
}
/**
* Draws the shapes at their current locations
* and colors.
*
* #param g
* the Graphics object to draw to
*/
public void paint (Graphics g)
{
// Clear the background to a nice light blue color.
g.setColor(new Color (0.8f, 0.8f, 1.0f));
g.fillRect(0, 0, this.getWidth(), this.getHeight());
// Draw all of the shapes.
for (Rect s : shapes)
s.draw(g);
}
/**
* This method is part of the MouseListener interface.
* Because we registered this application object as a listener
* to its own mouse events, this method will be automatically
* called whenever the mouse button is pressed down.
*
* In this method, we determine if the mouse click occurred
* in any of our shapes. If so, we record that shape object
* as the current shape. This has the effect of selecting
* a shape to drag around.
*
* #param e
* the mouse event
*/
public void mousePressed (MouseEvent e)
{
// Get the location of the mouse click within this window.
int x = e.getX ();
int y = e.getY ();
// Save it for later use.
lastX = x;
lastY = y;
// Determine if the mouse click is within any shape.
// If so, save the shape as the current shape.
for (Rect s : shapes)
if (s.isInside (x, y))
current = s;
}
/**
* This method is part of the MouseListener interface.
* Because we registered this applet object as a listener
* to its own mouse events, this method will be automatically
* called whenever the mouse button is let down.
*
* In this method, we mark the current shape as null. This
* has the effect of dropping whatever shape we are dragging
* around.
*
* #param e
* the mouse event
*/
public void mouseReleased (MouseEvent e)
{
current = null;
}
/**
* This method is part of the MouseMotionListener interface.
* Because we registered this applet object as a listener
* to its own mouse events, this method will be automatically
* called whenever the mouse is moved with the button pressed down.
*
* In this method, we adjust the position of the shape the user
* is dragging around.
*
* #param e
* the mouse event
*/
public void mouseDragged (MouseEvent e)
{
// Compute how far the mouse moved since the last event.
int x = e.getX ();
int y = e.getY ();
int deltaX = x - lastX;
int deltaY = y - lastY;
// Save the current mouse position.
lastX = x;
lastY = y;
// If the user is dragging around a shape, move it by
// the same amount that the mouse moved.
if (current != null)
{
current.move (deltaX, deltaY);
repaint ();
}
}
// Unused event methods (required by the interfaces).
public void mouseClicked (MouseEvent e) { }
public void mouseEntered (MouseEvent e) { }
public void mouseExited (MouseEvent e) { }
public void mouseMoved (MouseEvent e) { }
/* Above this point are the methods and variables that we use in the JPanel */
/* Below this point are the methods and variables that launch the application */
/* I violated separation of concerns. The JPanel and Application classes
* are merged, and 'main' is below. This works for simple code (like this
* lab), but it is not a good idea for larger projects.
*/
/**
* The application entry point.
*
* #param args unused
*/
public static void main (String[] args)
{
// Main runs in the 'main' execution thread, and the GUI
// needs to be built by the GUI execution thread.
// Ask the GUI thread to run our 'run' method (at some
// later time).
SwingUtilities.invokeLater(new ShapeMover());
// Done. Let the main thread of execution finish. All the
// remaining work will be done by the GUI thread.
}
/**
* Builds the GUI for this application. This method must
* only be called/executed by the GUI thread.
*/
public void run ()
{
JFrame f = new JFrame("Shape Mover 2021");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 'this' is our Runnable object, but it is also our JPanel.
f.setContentPane(this);
f.pack();
f.setLocationRelativeTo(null); // Centers window
f.setVisible(true);
}
}
Description
Given the following parameters:
Outer radius
Inner radius
Amount of regions
Starting angle (that second picture starts at 180 degrees)
Angle drawn (that second picture draws a total of 320 degrees from its starting angle)
How does one calculate the maximal size of the Images to draw so that they remain within their sector? On the left picture, I'm just using a hard-coded value because I haven't specifically been able to think of a nice, general, mathematical equation for that.
More variables could eventually come into play, if I ever decide to expand my library even more. Things such as the width of the separators or of the circumference's outline.
Code
This is what I use to draw everything but the children Actors:
/**
* Takes care of drawing everything that {#link #layout()} didn't.
* (Basically everything but the children Actors.)
*
* #param batch a Batch used to draw Drawables. The {#link #sd} is used to
* draw everything else.
* #param parentAlpha
*/
protected void drawWithShapeDrawer(Batch batch, float parentAlpha) {
/* Pre-calculating */
float bgRadian = MathUtils.degreesToRadians*style.totalDegreesDrawn;
float tmpOffset = MathUtils.degreesToRadians*style.startDegreesOffset;
int size = getChildren().size;
float tmpRad = bgRadian / size;
/* Background image */
if(style.background != null)
style.background.draw(batch, getX(), getY(), getWidth(), getHeight());
/* Rest of background */
if(style.backgroundColor != null) {
sd.setColor(style.backgroundColor);
sd.sector(getX()+style.radius, getY()+style.radius, style.radius-BG_BUFFER, tmpOffset, bgRadian);
}
/* Children */
vector2.set(getX()+style.radius, getY()+style.radius);
for(int i=0; i<size; i++) {
float tmp = tmpOffset + i*tmpRad;
drawChildWithoutSelection(vector2, i, tmp, tmpRad);
/* Separator */
drawChildSeparator(vector2, tmp);
}
/* The remaining last separator to be drawn */
drawChildSeparator(vector2, tmpOffset + size*tmpRad);
}
protected void drawChildSeparator(Vector2 vector2, float drawnRadianAngle) {
if(getChildren().size > 1 && style.separatorColor != null)
sd.line(pointAtAngle(vector22, vector2, style.innerRadius, drawnRadianAngle),
pointAtAngle(vector23, vector2, style.radius, drawnRadianAngle),
style.separatorColor, style.separatorWidth);
}
protected void drawChildWithoutSelection(Vector2 vector2, int index, float startAngle, float radian) {
if(style.childRegionColor != null) {
if(style.alternateChildRegionColor != null) {
sd.setColor(index%2 == 0 ? style.childRegionColor : style.alternateChildRegionColor);
sd.arc(vector2.x, vector2.y, (style.radius+style.innerRadius)/2, startAngle, radian, style.radius-style.innerRadius);
} else {
sd.setColor(style.childRegionColor);
sd.arc(vector2.x, vector2.y, (style.radius+style.innerRadius)/2, startAngle, radian, style.radius-style.innerRadius);
}
}
drawChildCircumference(vector2, startAngle, radian, style.radius - style.circumferenceWidth/2);
}
protected void drawChildCircumference(Vector2 vector2, float startAngle, float radian, float radius) {
if(style.circumferenceColor != null && style.circumferenceWidth > 0) {
sd.setColor(style.circumferenceColor);
sd.arc(vector2.x, vector2.y, radius, startAngle, radian, style.circumferenceWidth);
}
}
And this is how I'm laying out those children:
#Override
public void layout() {
float degreesPerChild = style.totalDegreesDrawn / getChildren().size;
float half = (float)1 / 2;
for (int i = 0; i < getChildren().size; i++) {
Actor actor = getChildren().get(i);
vector2.set((style.radius+style.innerRadius)/2, 0);
vector2.rotate(degreesPerChild*(i + half) + style.startDegreesOffset);
if(actor instanceof Image) { // todo: do this properly !
actor.setSize(30, 30);
}
actor.setPosition(vector2.x+style.radius, vector2.y+style.radius, Align.center);
}
}
Here is what I ended up doing:
/**
* Used to estimate the radius of a circle to be constrained within the widget
* according to the input parameters. Doubling the returned value would give
* you the size of a contained Actor which would roughly fill most of its
* sector, or possibly overflow slightly. It is suggested to adjust slightly
* the returned value by multiplying it with a factor of your choice.<br>
* It's basically the minimum between 3 different possible radius values
* based on certain layout properties.
*
* #param degreesPerChild the amount of degrees that a child's sector takes.
* #param actorDistanceFromCenter the distance at which the child Actor is
* positioned from the center of the widget.
* #return an estimated radius value for an Actor placed with the given
* constraints.
*/
public float getEstimatedRadiusAt(float degreesPerChild, float actorDistanceFromCenter) {
float tmp1 = actorDistanceFromCenter * MathUtils.sinDeg(degreesPerChild/2);
float tmp2 = getMaxRadius() - actorDistanceFromCenter;
float tmp3 = actorDistanceFromCenter - getInnerRadiusLength();
return Math.min(Math.min(tmp1, tmp2), tmp3);
}
I currently have a canvas where I will first draw an image before all the other canvas mouse-draw functions come in (to draw the boxes). I also have an undo function which will remove the last drawn box, clear the entire canvas and redraw all the remaining boxes back onto the canvas. However, after undoing, the image will somehow appear on top of the boxes and covering them, instead of below as it should be. I was able to fix this using z-index in HTML5 previously, but do not know how to do so using the Java way.
This is my Canvas.java (undo method is towards the end):
package com.vaadin.starter.beveragebuddy.ui.components;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.HasSize;
import com.vaadin.flow.component.HasStyle;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.html.Label;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.dom.Element;
import com.vaadin.flow.dom.ElementFactory;
import com.vaadin.flow.shared.Registration;
import com.vaadin.starter.beveragebuddy.backend.MainLayout;
import elemental.json.JsonObject;
import java.util.ArrayList;
import java.util.List;
/**
* Canvas component that you can draw shapes and images on. It's a Java wrapper
* for the
* <a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API">HTML5
* canvas</a>.
* <p>
* Use {#link #getContext()} to get API for rendering shapes and images on the
* canvas.
* <p>
*/
#Tag("canvas")
#SuppressWarnings("serial")
public class Canvas extends Component implements HasStyle, HasSize {
private static CanvasRenderingContext2D context;
private Element element;
private boolean mouseSelect = false;
private boolean mouseIsDown = false;
private double endX;
private double endY;
public static int boxCount = 0;
public static boolean undoCalled = false;
public static ArrayList <BoundingBox> arrayBoxes = new ArrayList<BoundingBox>();
public static ArrayList <MousePosition> mousePosArray = new ArrayList<MousePosition>();
public static ArrayList <SelectBox> selectBoxes = new ArrayList<SelectBox>();
private List<Runnable> mouseMoveListeners = new ArrayList<>(0);
public static ArrayList<BoundingBox> getArrayBoxes() {
return arrayBoxes;
}
public static ArrayList<MousePosition> getMousePosArray() {
return mousePosArray;
}
public static void setMousePosArray(ArrayList<MousePosition> mousePosArray) {
Canvas.mousePosArray = mousePosArray;
}
/**
* Creates a new canvas component with the given size.
* <p>
* Use the API provided by {#link #getContext()} to render graphics on the
* canvas.
* <p>
* The width and height parameters will be used for the canvas' coordinate
* system. They will determine the size of the component in pixels, unless
* you explicitly set the component's size with {#link #setWidth(String)} or
* {#link #setHeight(String)}.
*
// * #param width
// * the width of the canvas
// * #param height
// * the height of the canvas
// */
public Registration addMouseMoveListener(Runnable listener) {
mouseMoveListeners.add(listener);
return () -> mouseMoveListeners.remove(listener);
}
public Canvas(int width, int height) {
context = new CanvasRenderingContext2D(this);
context.drawImage("https://freedesignfile.com/upload/2016/10/Red-Clouds-and-Prairie-Background.jpg", 0, 0);
element = getElement();
element.getStyle().set("border", "1px solid");
getElement().setAttribute("width", String.valueOf(width));
getElement().setAttribute("height", String.valueOf(height));
element.addEventListener("mousedown", event -> { // Retrieve Starting Position on MouseDown
Element boundingBoxResult = ElementFactory.createDiv();
element.appendChild(boundingBoxResult);
JsonObject evtData = event.getEventData();
double xBox = evtData.getNumber("event.x");
double yBox = evtData.getNumber("event.y");
boundingBoxResult.setAttribute("data-x", String.format("%f", xBox));
boundingBoxResult.setAttribute("data-y", String.format("%f", yBox));
BoundingBox newBox = new BoundingBox("","", xBox, yBox, 0.0, 0.0);
arrayBoxes.add(newBox);
SelectBox select = new SelectBox(xBox, 0.0, yBox, 0.0);
selectBoxes.add(0, select);
mouseIsDown=true;
mouseMoveListeners.forEach(Runnable::run);
}).addEventData("event.x").addEventData("event.y");
element.addEventListener("mouseup", event -> { // Draw Box on MouseUp
Element boundingBoxResult2 = ElementFactory.createDiv();
element.appendChild(boundingBoxResult2);
JsonObject evtData2 = event.getEventData();
endX = evtData2.getNumber("event.x");
endY = evtData2.getNumber("event.y");
boundingBoxResult2.setAttribute("end-x", String.format("%f", endX));
boundingBoxResult2.setAttribute("end-y", String.format("%f", endY));
// System.out.println(endX);
// System.out.println(endY);
double xcoordi = 0;
double ycoordi = 0;
double boxWidth = 0;
double boxHeight = 0;
// for (int i = 0; i < arrayBoxes.size(); i++) {
System.out.println(endX);
System.out.println(endY);
arrayBoxes.get(boxCount).setWidth(endX, arrayBoxes.get(boxCount).xcoordi);
arrayBoxes.get(boxCount).setHeight(endY, arrayBoxes.get(boxCount).ycoordi);
xcoordi = arrayBoxes.get(boxCount).getXcoordi();
ycoordi = arrayBoxes.get(boxCount).getYcoordi();
boxWidth = arrayBoxes.get(boxCount).getWidth();
boxHeight = arrayBoxes.get(boxCount).getHeight();
boxCount++;
mouseIsDown=false;
context.beginPath();
context.setStrokeStyle("green");
context.setLineWidth(2);
context.strokeRect(xcoordi, ycoordi, boxWidth, boxHeight);
context.stroke();
context.fill();
SelectBox select = new SelectBox(endX, 0.0, endY, 0.0);
selectBoxes.add(1, select);
// if (selectBoxes.get(1).getSelectEndX() == selectBoxes.get(0).getSelectStartX()){
// mouseSelect = true;
// context.beginPath();
// context.setStrokeStyle("yellow");
// context.setLineWidth(2);
// context.strokeRect(arrayBoxes.get(i).xcoordi, arrayBoxes.get(i).ycoordi, arrayBoxes.get(i).boxWidth, arrayBoxes.get(i).boxHeight);
// context.fill();
// }
System.out.println(arrayBoxes.toString());
//
// for (int i = 0; i < arrayBoxes.size(); i++){
// if(arrayBoxes.get(i).xcoordi)
// if (endX > arrayBoxes.get(i).xcoordi){
// if (endX < arrayBoxes.get(i).endY)
// }
// }
mouseMoveListeners.forEach(Runnable::run);
}).addEventData("event.x").addEventData("event.y");
element.addEventListener("mousemove", event -> { // Retrieve Mouse Position when Moving
JsonObject mousePos = event.getEventData();
double mouseX = mousePos.getNumber("event.x");
double mouseY = mousePos.getNumber("event.y");
MousePosition currentPos = new MousePosition(mouseX, mouseY);
mousePosArray.add(0, currentPos);
setMousePosArray(mousePosArray);
mouseMoveListeners.forEach(Runnable::run);
}).addEventData("event.x").addEventData("event.y");
}
public static void undoLast() {
undoCalled = true;
if (arrayBoxes.size() > 0) {
arrayBoxes.remove(arrayBoxes.size() - 1);
}
System.out.println(arrayBoxes.toString());
System.out.println(arrayBoxes.size());
context.clearRect(0, 0, 1580, 700);
context.drawImage("https://freedesignfile.com/upload/2016/10/Red-Clouds-and-Prairie-Background.jpg", 0, 0);
for (int i = 0; i < arrayBoxes.size(); i++){
context.beginPath();
context.setStrokeStyle("green");
context.setLineWidth(2);
context.strokeRect(arrayBoxes.get(i).xcoordi, arrayBoxes.get(i).ycoordi, arrayBoxes.get(i).boxWidth, arrayBoxes.get(i).boxHeight);
context.fill();
}
boxCount--;
System.out.println("Box Count: " + boxCount);
}
/**
* Gets the context for rendering shapes and images in the canvas.
* <p>
* It is a Java wrapper for the <a href=
* "https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D">same
* client-side API</a>.
*
* #return the 2D rendering context of this canvas
*/
public CanvasRenderingContext2D getContext() {
return context;
}
/**
* {#inheritDoc}
* <p>
* <b>NOTE:</b> Canvas has an internal coordinate system that it uses for
* drawing, and it uses the width and height provided in the constructor.
* This coordinate system is independent of the component's size. Changing
* the component's size with this method may scale/stretch the rendered
* graphics.
*/
#Override
public void setWidth(String width) {
HasSize.super.setWidth(width);
}
/**
* {#inheritDoc}
* <p>
* <b>NOTE:</b> Canvas has an internal coordinate system that it uses for
* drawing, and it uses the width and height provided in the constructor.
* This coordinate system is independent of the component's size. Changing
* the component's size with this method may scale/stretch the rendered
* graphics.
*/
#Override
public void setHeight(String height) {
HasSize.super.setHeight(height);
}
/**
* {#inheritDoc}
* <p>
* <b>NOTE:</b> Canvas has an internal coordinate system that it uses for
* drawing, and it uses the width and height provided in the constructor.
* This coordinate system is independent of the component's size. Changing
* the component's size with this method may scale/stretch the rendered
* graphics.
*/
#Override
public void setSizeFull() {
HasSize.super.setSizeFull();
}
public void addComponent(Label label) {
}
}
Any help is much appreciated, thank you!
I believe your issue is due to one or both of these issues
When drawing the image, you correctly wait for it to load before actually drawing it to the canvas (image.onload = ...). This means that your code might start loading the image, then it draws all the boxes, and then the image loads so that it is drawn on top.
You run the image drawing script on beforeClientResponse, which means it might get called after all the code for drawing the boxes is called.
The simplest solution, if you always want to have an image as the background, is to use two canvases on top of each other (with absolute positioning, for example). This way, you can always draw the images to the background canvas, and all boxes to the foreground canvas. A bonus of this is that you don't have to redraw the background even if you clear the foreground canvas.
need some help here. Working on "Classes and Object-Oriented Development" and could use some help with both my logic and code for a question in the textbook.
Question: I am asked to Modify my previous example of my Rectangle class to override the equals() and toString() methods. Two rectangles are equal when they both have the same length and width.
My approach: I tried to change it to do this, and then decided it would be easier to compare by areas, rather than comparing both by width and length, so below is what I have so far. Let me know if you have any ideas to help. There is a previous example of the equals() method that compares a circle's radius but isnt helping when comparing 2 different things. Thanks before hand all ! If your wondering why they are all not their own separate files, I haven't gotten there in the chapter yet so it's alot to look at I know ;P
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package chapter8javaExamples;
/**
*
* #author Eric
*/
public class Rectangle {
private double length, width;
/**
* constructor
* pre: none
* post: A rectangle class is created.
*/
public Rectangle() {
length = 2; //default length
width = 4; //default width
}
/**
* constructor
* pre: none
* post: A rectangle object is created with length and width.
*/
public Rectangle (double l, double w) {
length = l;
width = w;
}
/**
* Changes the length of the rectangle
* pre: none
* post: Length has been changed.
*/
public void setLength (double newLength) {
length = newLength;
}
/**
* Changes the width of the rectangle.
* pre: none
* post: Width has been changed.
*/
public void setWidth (double newWidth) {
width = newWidth;
}
/**
* Returns the length of the rectangle.
* pre: none
* post: The length of the rectangle has been returned.
*/
public double getLength() {
return(length);
}
/**
* Returns the width of the rectangle.
* pre: none
* post: The width of the rectangle has been returned.
*/
public double getWidth() {
return(width);
}
/**
* Returns the area of rectangle
* pre: none
* post: The area of the rectangle is returned
*/
public double area() {
double triArea;
triArea = length * width;
return(triArea);
}
/**
* Returns the perimeter of the rectangle
* pre: none
* post: The perimeter of the rectangle is returned
*/
public double perimeter() {
double triPer;
triPer = length + width + length + width;
return(triPer);
}
/**
* Displays the formula for area of a rectangle.
* pre: none
* post: The formula is displayed.
*/
public static void displayAreaFormula(){
System.out.println("The formula for the area of a rectangle is a=l*w");
}
/**
* Determines if the object is equal to another
* Circle object.
* pre: c is a Circle object.
* post: true has been returned if the objects have
* the same radii, false otherwise.
*/
public boolean equals(Object r) {
Rectangle testObj = (Rectangle) r;
Rectangle testObj2 = (Rectangle) r2;
if (testObj.getArea() == area && testObj2.getArea == area()) {
return(true);
} else {
return(false);
}
}
/**
* Returns a String that represents the Circle object.
* pre: none
* post: A string representing the Circle object has
* been returned.
*/
public String toString(){
String rectangleString;
rectangleString = "Rectangle has the Area " + length*width;
return(rectangleString);
}
/**
*
* #param args
*/
public static void main(String [] args){
Rectangle spot = new Rectangle();
Rectangle spot2 = new Rectangle(5, 9);
System.out.println("Area is: " + spot.area());
System.out.println("Perimeter: " + spot.perimeter());
Rectangle.displayAreaFormula();
}
}
I don't think that comparing the areas is a good idea in the equals method, because a rectangle that is 2x8 would equal a rectangle that is 4x4, because both areas are 16. This contradicts your requirement:
Two rectangles are equal when they both have the same length and width.
Here, your r2 variable is undefined. But beyond that, the equals method shouldn't compare two other objects, it should compare this object to another object.
You should return true if the r object is a Rectangle and this rectangle's length matches the other rectangle's length and this rectangle's width matches the other rectangle's width.
Your equals method should always have the following structure:
public boolean equals(Object r) {
if(r == null || !r instanceof Rectangle) return false;
// rest of the code
}
This is because you don't want to perform operations on a null-reference (which would throws errors), and this can't equals null anyway. Secondly: if r is not an instance of the rectangle class, we can quit before having to perform other operations, because a Rectangle would not equal a String, or a Circle.
Now, to get to your question: if you want to check on equality purely by width and length, I would write the method like this:
public boolean equals(Object r) {
if(r == null || !r instanceof Rectangle) return false;
if(length == r.length && width == w.width) return true;
return false;
}
This compares the width and length. If they are both equal, two rectangles are equal. You are comparing the area, but this could give false positives. Take this example:
Rectangle r1;
Rectangle r2;
r1.width = 10;
r1.length = 5;
r2.width = 5;
r2.length = 10;
Your code would produce a positive, while these rectangles are orientated differently.
Two rectangles are equal when they have both same length and width.
Are these following rectangles the same?
and
Hey! Both have the same area don't they?
So in short, no you have use && to see if the length and breadth of both are equal or you could compare the .toString()s of both rectangles to see if they are exact.
To add to the other answers (read those first)
If you are comparing "physical" objects (a block of wood for example) then you might want to compare length to width and width to length as well. The orientation a user inputs might be submitted differently for two of the same objects. Consider this when reading your requirements.
I am developing photography apps in that I overlay an image with text.
Here is my code:
Bitmap mBitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.themes11);
// create a mutable bitmap with the same size as the background image's size
bmOverlay = Bitmap.createBitmap(mBitmap.getWidth(),
mBitmap.getHeight(), Bitmap.Config.ARGB_4444);
// create a canvas on which to draw
Canvas canvas = new Canvas(bmOverlay);
TextPaint paint = new TextPaint();
paint.setColor(Color.RED);
paint.setTextSize(40);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
// if the background image is defined in main.xml, omit this line
canvas.drawBitmap(mBitmap, 0, 0, null);
// draw the text and the point
canvas.drawPoint(50, 100, paint);
// canvas.drawText(InstaTextActivity.CurrentWord, 300, 200, paint);
StaticLayout layout = new StaticLayout(InstaTextActivity.CurrentWord,
paint, display.getHeight(),
android.text.Layout.Alignment.ALIGN_NORMAL, (float) 1.0,
(float) 0.0, true);
canvas.translate(width / 5, height / 5);
layout.draw(canvas);
imageview_img.setImageBitmap(bmOverlay);
In this code I overlay the text on screen width/2 and height/2 it will display on top the image but I want the text to be center-aligned. Also when I write a large text it will align form center to right.
Have a look at the images to see how I want it:
The Image Background:
And the result I want:
Use the below methods to measure the height and width of the text.
Then when drawing the text on canvas
left = width/2 - textWidth/2
top = height/2 - textHeight/2
But if you need a multiple line text for long texts, it will be a bit tricky.
/**
* Method to get the height of the paint
*
* #param brush The TextPaint used to paint the text
* #param text The text which needs to be measured
* #return height of the text
*/
public static int measureTextHeight(Paint brush, String text) {
Rect result = new Rect();
// Measure the text rectangle to get the height
brush.getTextBounds(text, 0, text.length(), result);
return result.height();
}
/**
* Method to get the width of the paint
*
* #param brush The TextPaint used to paint the text
* #param text The text which needs to be measured
* #return width of the text
*/
public static int measureTextWidth(Paint brush, String text) {
Rect result = new Rect();
// Measure the text rectangle to get the height
brush.getTextBounds(text, 0, text.length(), result);
return result.width();
}
i using this. working for me.
public Bitmap drawMultilineTextToBitmap(Context gContext,
int gResId,
String gText) {
// prepare canvas
Resources resources = gContext.getResources();
float scale = resources.getDisplayMetrics().density;
Bitmap bitmap = BitmapFactory.decodeResource(resources, gResId);
android.graphics.Bitmap.Config bitmapConfig = bitmap.getConfig();
// set default bitmap config if none
if(bitmapConfig == null) {
bitmapConfig = android.graphics.Bitmap.Config.ARGB_8888;
}
// resource bitmaps are imutable,
// so we need to convert it to mutable one
bitmap = bitmap.copy(bitmapConfig, true);
Canvas canvas = new Canvas(bitmap);
// new antialiased Paint
TextPaint paint=new TextPaint(Paint.ANTI_ALIAS_FLAG);
// text color - #3D3D3D
paint.setColor(Color.rgb(61, 61, 61));
// text size in pixels
paint.setTextSize((int) (14 * scale));
// text shadow
paint.setShadowLayer(1f, 0f, 1f, Color.WHITE);
// set text width to canvas width minus 16dp padding
int textWidth = canvas.getWidth() - (int) (16 * scale);
// init StaticLayout for text
StaticLayout textLayout = new StaticLayout(
gText, paint, textWidth, Layout.Alignment.ALIGN_CENTER, 1.0f, 0.0f, false);
// get height of multiline text
int textHeight = textLayout.getHeight();
// get position of text's top left corner
float x = (bitmap.getWidth() - textWidth)/2;
float y = (bitmap.getHeight() - textHeight)/2;
// draw text to the Canvas center
canvas.save();
canvas.translate(x, y);
textLayout.draw(canvas);
canvas.restore();
return bitmap;
}
source : http://www.skoumal.net/en/android-drawing-multiline-text-on-bitmap/
This is not a very refined approach(Not optimized for memory usage) but does the job. You will need to modify the code in order to split at the string keeping words intact. Hope this helps.
package org.edu.abhi;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
/**
* #author Abhishek_Nandi
*
*/
public class DummyUserSpace extends View {
/***************************************************************************
* Calls superclass constructor. This will call {#link #init(Context)}
*
* #param context
* The Context the view is running in, through which it can
* access the current theme, resources, etc.
**************************************************************************/
public DummyUserSpace(Context context) {
super(context);
init(context);
}
/***************************************************************************
* Calls superclass constructor. This will call {#link #init(Context)}
*
* #param context
* The Context the view is running in, through which it can
* access the current theme, resources, etc.
* #param attrs
* The attributes of the XML tag that is inflating the view.
* #param defStyle
* The default style to apply to this view. If 0, no style will
* be applied (beyond what is included in the theme). This may
* either be an attribute resource, whose value will be retrieved
* from the current theme, or an explicit style resource.
**************************************************************************/
public DummyUserSpace(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}
/***************************************************************************
* Calls superclass constructor. This will call {#link #init(Context)}
*
* #param context
* The Context the view is running in, through which it can
* access the current theme, resources, etc.
* #param attrs
* The attributes of the XML tag that is inflating the view.
**************************************************************************/
public DummyUserSpace(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
/**
* Width of the View
*/
int viewWidth = 0;
/**
* Height of the View
*/
int viewHeight = 0;
/**
* {#link Paint} which is used to draw {#link #text}
*/
Paint textPaint;
/**
* The text which needs to be drawn
*/
String text = "can be spared the burden of having to perform manual memory management. In some languages, memory for the creation of objects is implicitly allocated on the stack, or explicitly allocated and deallocated from the heap. In the latter case the responsibility of managing memory resides with the programmer. If the program does not deallocate an object, a memory leak occurs. If the program attempts to access or deallocate memory that has already been deallocated, the result is undefined and difficult to predict, and the program is likely to become unstable and/or crash. This can be partially remedied by the use of smart pointers, but these add overhead and complexity. Note that garbage collection does not prevent \"logical\" memory leaks, i.e. those where the memory is still referenced but never used.. o have as few implementation dependencies as possible. It is intended to let application developers \"write once, run anywhere\" (WORA), meaning that code that runs on one platform does not need to be recompiled to run on another. Java is as of 2012 one of the most popular programming languages in use, particularly for client-server web applications, with a reported 10 million users";
/**
* Common constructor routine
*
* #param context
* The Context the view is running in. It is used to get the
* density of the device
*/
private void init(Context context) {
textPaint = new Paint();
textPaint.setColor(Color.WHITE);
textPaint.setTextSize(40);
textPaint.setStrokeWidth(6.0f);
WindowManager manager = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
manager.getDefaultDisplay().getMetrics(outMetrics);
padding *= outMetrics.density;
lineSpacing *= outMetrics.density;
}
/**
* Split the string and compute the {#link #startY}, {#link #textHeight}
* which is required for drawing the view
*/
private void prepareForDrawing() {
viewWidth = getWidth();
viewHeight = getHeight();
if (viewHeight == 0) {
return;
}
textHeight = Utility.measureTextHeight(textPaint, text);
if (0 == textHeight) {
return;
}
maxLines = (viewHeight - 2 * padding) / (textHeight + lineSpacing);
prepareMultiLineText(textPaint, text);
int noOfLines = splittedText.size();
int section = noOfLines / 2;
int center = viewHeight / 2;
if (noOfLines % 2 == 0) {
center -= lineSpacing / 2;
} else {
center -= textHeight / 2;
}
startY = center - (section - 1) * (textHeight + lineSpacing)
+ lineSpacing;
}
/**
* The starting position from where the view will start drawing
*/
private int startY = 0;
/**
* Height of the text
*/
private int textHeight = 0;
/**
* Maximum lines this view can hold
*/
private int maxLines = 1;
/**
* Padding from the view border
*/
private int padding = 20;
/**
* Spacing between each line
*/
private int lineSpacing = 10;
private final String loadingText = "Loading..";
/*
* (non-Javadoc)
*
* #see android.view.View#onDraw(android.graphics.Canvas)
*/
#Override
protected void onDraw(Canvas canvas) {
if (!computationComplete) {
new DrawComputations().execute();
canvas.drawText(
loadingText,
getWidth() / 2
- Utility.measureTextWidth(textPaint, loadingText)
/ 2,
getHeight() / 2
- Utility.measureTextHeight(textPaint, loadingText)
/ 2, textPaint);
} else {
for(int count = 0; count<splittedText.size() ; count++){
String trimmed = splittedText.get(count);
//System.out.println(trimmed);
canvas.drawText(
trimmed,
viewWidth / 2
- Utility.measureTextWidth(textPaint, trimmed)
/ 2, startY + (count - 1)
* (textHeight + lineSpacing), textPaint);
}
}
}
/**
* Denotes the computation has completed and the view is ready to be drawn
*/
boolean computationComplete = false;
/**
* This {#link AsyncTask} performs the computation in background and updates
* the view when computation is finished and the view is ready to be drawn
*
* #author Abhishek_nandi
* #version 1.0
*/
class DrawComputations extends AsyncTask<Void, Void, Void> {
/*
* (non-Javadoc)
*
* #see android.os.AsyncTask#doInBackground(Params[])
*/
#Override
protected Void doInBackground(Void... params) {
prepareForDrawing();
computationComplete = true;
return null;
}
/*
* (non-Javadoc)
*
* #see android.os.AsyncTask#onPostExecute(java.lang.Object)
*/
#Override
protected void onPostExecute(Void result) {
invalidate();
}
}
/**
* Collection which holds the multi-line text
*/
private List<String> splittedText = new ArrayList<String>();
/**
* This method is responsible for stripping {#link #text} into individual
* lines in order to form the multi line text. This method can be used as a
* utility.
*
* #param paint
* The {#link Paint} which is used to draw the text
* #param str
* The string which needs to be stripped
*/
private void prepareMultiLineText(Paint paint, String str) {
if (str == null || str.trim().length() == 0)
return;
str = str.trim();
String result = str;
int boxWidth = viewWidth;
try {
float textWidth = paint.measureText(str) + 2 * padding;
result = str;
while (textWidth > boxWidth) {
if (result.length() == 0)
break;//keeping the entire word intact//if(result.lastIndexOf(" ")!=-1){result = result.substring(0, result.lastIndexOf(" "))}else
result = result.substring(0, result.length() - 1);
textWidth = paint.measureText(result) + 2 * padding;
}
result = result.trim();
boolean exceeded = false;
if (splittedText.size() == maxLines) {
exceeded = true;
result = result.substring(0, result.length()-2).concat("..");
}
splittedText.add(result);
if (!exceeded && result.length() != str.length()) {
prepareMultiLineText(textPaint, str.substring(result.length()));
}
} catch (Exception e) {
Log.e("CustomView", "prepareMultiLineText", e);
}
}
} // END of class
// END of file
You should use StaticLayout for this. It measures and draws multiline text, handling line wrapping, line spacing, alignment etc.
StaticLayout layout = new StaticLayout("your long text", textPaint,
pixelsToFitWidthTo, Layout.Alignment.ALIGN_NORMAL, 1f, 0f, true);
int boxHeight = layout.getHeight(); // measure
The text can even be HTML formatted, just wrap your text in Html.fromHtml():
Html.fromHtml("your long <b>and bold</b> text");