How to add rectangles on top of existing rectangle in canvas - java

I'm trying to add some red rectangles within my existing canvas on top of specific boxes exactly like the expected result image but they don't appear at all as my code shows the current undesired outcome when I deploy my app. My code is to create 4 rectangles on the top row and 4 rectangles on the bottom row but I only want this to be added on top of boxes 2-6 but I know extra code needs to be added for the red rectangles on top of boxes 1 & 7. Does anyone know what I'm doing wrong and how to fix this? All help would be appreciated.
public class RectangleTextView extends View {
private final Paint mBlackPaint = new Paint();
private final Paint mRedPaint = new Paint();
private final TextPaint mTextPaint;
public RectangleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
int valueInDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
int valueInSp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
mRedPaint.setColor(Color.parseColor("#CC3333"));
mBlackPaint.setAntiAlias(false);
mBlackPaint.setColor(Color.BLACK);
mBlackPaint.setStrokeWidth(valueInDp);
mBlackPaint.setStyle(Paint.Style.STROKE);
mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setTextSize(valueInSp);
mWindowPaint = new Paint();
mWindowPaint.setColor(Color.parseColor("#CC3333"));
mWindowPaint.setStrokeWidth(valueInDp);
}
private Paint mWindowPaint;
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (getWidth() == 0)
return;
//initialise red rectangles
int w = canvas.getWidth();
int h = canvas.getHeight();
int rectWidth = w / 5;
int space = w / 15;
int topRectHeight = getPaddingTop();
int bottomRectHeight = getPaddingBottom();
//draw end rectangles
int mSideRectWidth = 10;
canvas.drawRect(0, 0, mSideRectWidth, getHeight(), mRedPaint); //draw left end rectangle
canvas.drawRect(getWidth() - mSideRectWidth, 0, getWidth(), getHeight(), mRedPaint); //draw right end rectangle
//draw grey boxes
setBackgroundColor(Color.parseColor("#808080"));
int boxWidth = (getWidth() - mSideRectWidth) / 7;
//draw text views
for (int i = 0; i < 7; i++) {
canvas.drawText(Integer.toString(i + 1), (i * boxWidth + 10) + (boxWidth / 2), ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)), mTextPaint);
}
//draw black lines
for (int i = 1; i < 7; i++) {
canvas.drawLine(mSideRectWidth + boxWidth * i, 0, mSideRectWidth + boxWidth * i, getHeight(), mBlackPaint);
}
//draw red windows
for (int i = 0; i < 4; i++) {
mWindowPaint.setStyle(Paint.Style.STROKE);//add this
int left = i * (rectWidth + space);
int right = left + rectWidth;
if (i == 1){
mWindowPaint.setStyle(Paint.Style.FILL); // change to this
}
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, mWindowPaint);
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, mWindowPaint);
}
}
}
expected result
current undesired outcome
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin" tools:context=".MainActivity">
<com.apptacularapps.car.RectangleTextView
android:layout_width="100dp"
android:layout_height="45dp"
android:paddingTop="10dp"
android:paddingBottom="10dp"
android:background="#808080"
android:gravity="center"/>
</RelativeLayout>
MainActivity.java
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}

Try this:
public class RectangleTextView extends View {
private final Paint mBlackPaint = new Paint();
private final Paint mRedPaint = new Paint();
private final TextPaint mTextPaint;
public RectangleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
int valueInDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
int valueInSp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
mRedPaint.setColor(Color.parseColor("#CC3333"));
mBlackPaint.setAntiAlias(false);
mBlackPaint.setColor(Color.BLACK);
mBlackPaint.setStrokeWidth(valueInDp);
mBlackPaint.setStyle(Paint.Style.STROKE);
mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setTextSize(valueInSp);
mWindowPaint = new Paint();
mWindowPaint.setColor(Color.parseColor("#CC3333"));
mWindowPaint.setStrokeWidth(valueInDp);
}
private Paint mWindowPaint;
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (getWidth() == 0)
return;
//initialise red rectangles
int h = canvas.getHeight();
int topRectHeight = getPaddingTop();
int bottomRectHeight = getPaddingBottom();
//draw end rectangles
int mSideRectWidth = 10;
canvas.drawRect(0, 0, mSideRectWidth, getHeight(), mRedPaint); //draw left end rectangle
canvas.drawRect(getWidth() - mSideRectWidth, 0, getWidth(), getHeight(), mRedPaint); //draw right end rectangle
//draw grey boxes
setBackgroundColor(Color.parseColor("#808080"));
int boxWidth = (getWidth() - mSideRectWidth) / 7;
int redRectWidth = boxWidth / 5;
int redRectSpace = redRectWidth / 3;
//draw text views
for (int i = 0; i < 7; i++) {
canvas.drawText(Integer.toString(i + 1), (i * boxWidth + 10) + (boxWidth / 2), ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)), mTextPaint);
int baseStartX = i * boxWidth;
//draw red windows
for (int j = 0; j < 4; j++) {
mWindowPaint.setStyle(Paint.Style.STROKE);//add this
int left = mSideRectWidth + baseStartX + (j * (redRectWidth + redRectSpace));
int right = left + redRectWidth;
if (j == 1) {
mWindowPaint.setStyle(Paint.Style.FILL); // change to this
}
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, mWindowPaint);
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, mWindowPaint);
}
}
//draw black lines
for (int i = 1; i < 7; i++) {
int startX = mSideRectWidth + boxWidth * i;
int startY = 0;
int stopX = mSideRectWidth + boxWidth * i;
int stopY = getHeight();
canvas.drawLine(startX, startY, stopX, stopY, mBlackPaint);
}
}
}

the problem was that you created only 4 rectangles in the screen witdh size, not in the number cell size.
here is the code:
public class RectangleTextView extends View {
private final Paint mBlackPaint = new Paint();
private final Paint mRedPaint = new Paint();
private final TextPaint mTextPaint;
public RectangleTextView(Context context, AttributeSet attrs) {
super(context, attrs);
int valueInDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 1, getResources().getDisplayMetrics());
int valueInSp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 20, getResources().getDisplayMetrics());
mRedPaint.setColor(Color.parseColor("#CC3333"));
mBlackPaint.setAntiAlias(false);
mBlackPaint.setColor(Color.BLACK);
mBlackPaint.setStrokeWidth(valueInDp);
mBlackPaint.setStyle(Paint.Style.STROKE);
mTextPaint = new TextPaint(TextPaint.ANTI_ALIAS_FLAG);
mTextPaint.setColor(Color.BLACK);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextPaint.setTextSize(valueInSp);
mWindowPaint = new Paint();
mWindowPaint.setColor(Color.parseColor("#CC3333"));
mWindowPaint.setStrokeWidth(valueInDp);
}
private Paint mWindowPaint;
Rect rect = new Rect();
Rect rect2 = new Rect();
#Override protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (getWidth() == 0)
return;
//initialise red rectangles
int w = canvas.getWidth();
int h = canvas.getHeight();
int rectWidth = ((w - 20) / 7) / 5;
int space = ((w - 20) / 7) / 15;
int topRectHeight = getPaddingTop();
int bottomRectHeight = getPaddingBottom();
//draw end rectangles
int mSideRectWidth = 10;
canvas.drawRect(0, 0, mSideRectWidth, getHeight(), mRedPaint); //draw left end rectangle
canvas.drawRect(getWidth() - mSideRectWidth, 0, getWidth(), getHeight(), mRedPaint); //draw right end rectangle
//draw grey boxes
setBackgroundColor(Color.parseColor("#808080"));
int boxWidth = (getWidth() - mSideRectWidth) / 7;
//draw text views
for (int i = 0; i < 7; i++) {
canvas.drawText(Integer.toString(i + 1), (i * boxWidth + 10) + (boxWidth / 2), ((canvas.getHeight() / 2) - ((mTextPaint.descent() + mTextPaint.ascent()) / 2)), mTextPaint);
}
//draw black lines
for (int i = 1; i < 7; i++) {
canvas.drawLine(mSideRectWidth + boxWidth * i, 0, mSideRectWidth + boxWidth * i, getHeight(), mBlackPaint);
}
//draw red windows
for (int index = 0; index < 7; index++) {
if (index == 0 || index == 6) {
for (int i = 0; i < 3; i++) {
mWindowPaint.setStyle(Paint.Style.STROKE);//add this
int left = (i * (rectWidth + space)) + (index * boxWidth) + 13 + rectWidth/2 + space/2;
int right = left + rectWidth;
rect.set(left, 0, right, topRectHeight);
canvas.drawRect(rect, mWindowPaint);
if (index == 0 && i == 1) {
mWindowPaint.setStyle(Paint.Style.FILL); // change to this
}
rect2.set(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, mWindowPaint);
}
} else {
for (int i = 0; i < 4; i++) {
mWindowPaint.setStyle(Paint.Style.STROKE);//add this
int left = (i * (rectWidth + space)) + (index * boxWidth) + 13;
int right = left + rectWidth;
rect.set(left, 0, right, topRectHeight);
canvas.drawRect(rect, mWindowPaint);
rect2.set(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, mWindowPaint);
}
}
}
}
}
this is the full code perfectly working for me. if you have any question or doubt feel free to post it :)
this is how i see them:

You are drawing all of the rectangles, but it looks like you want to skip all of the "odd" rectangles - or every second rectangle... and be sure to change the color to "red" - something like this:
//draw red windows
for (int i = 0; i < 4; i++) {
mWindowPaint.setStyle(Paint.Style.STROKE);//add this
int left = i * rectWidth;
int right = left + rectWidth;
if (i == 1){
mWindowPaint.setStyle(Paint.Style.FILL); // change to this
}
if (i % 2 == 0) {
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, mRedPaint);
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, mRedPaint);
}
}
}
EDIT:
I think the "filled" rectangle on the bottom is supposed to be more like:
//draw red windows
for (int i = 0; i < 4; i++) {
int left = i * rectWidth;
int right = left + rectWidth;
mWindowPaint.setStyle(Paint.Style.STROKE);//add this
if (i % 2 == 0) {
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, mRedPaint);
if (i == 1){
mWindowPaint.setStyle(Paint.Style.FILL); // change to this
}
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, mRedPaint);
}
}
}

Related

How to make object dissapear when hit

I was working on a brick breaker game in proccessing, and was trying to create the collision system for the game. I was able to identify when a collision happens between the ball and the brick, but I was not able to to make the brick dissapear when it gets hit by the ball. How do I do this? I would also appreciate a explanation, as I am a beginner.
Thanks.
color black = color(0,0,0);
color red = color(255,0,0);
color white = color(255,255,255);
float ballx = 412.5, bally = 600, balld = 20, ballr = balld/2, paddleX = 362.5, paddleY = 650;
float paddleW = 100, paddleH = 15;
float ballspdX, ballspdY;
boolean ball_drop = true;
float direction_choice;
float[] brickX = new float[10];
float[] brickY = new float[5];
float brickW = 50, brickH = 25;
void setup(){
size(825,800);
surface.setTitle("Brick breaker");
noCursor();
smooth();
brickX[0] = 50;
brickX[1] = 125;
brickX[2] = 200;
brickX[3] = 275;
brickX[4] = 350;
brickX[5] = 425;
brickX[6] = 500;
brickX[7] = 575;
brickX[8] = 650;
brickX[9] = 725;
brickY[0] = 50;
brickY[1] = 125;
brickY[2] = 200;
brickY[3] = 275;
brickY[4] = 350;
}
void paddle(){
noStroke();
fill(white);
rect(paddleX, paddleY, paddleW, paddleH);
}
void ball(){
noStroke();
fill(red);
circle(ballx, bally, balld);
}
void draw(){
background(black);
paddle();
ball();
if (bally + ballr == paddleY && ballx > paddleX && ballx < paddleX + (paddleW / 2)){
ball_drop = false;
ballspdY = -ballspdY;
ballspdX = -4;
}
/*
if (bally + ballr == paddleY && ballx > paddleX && ballx < paddleX + paddleW){
ball_drop = false;
ballspdY = -ballspdY;
direction_choice = int(random(1,3));
if (direction_choice == 1){
ballspdX = 4;
}
if (direction_choice == 2){
ballspdX = -4;
}
}
println(direction_choice);
*/
if (bally + ballr == paddleY && ballx > paddleX + (paddleW /2) && ballx < paddleX + paddleW){
ball_drop = false;
ballspdY = -ballspdY;
ballspdX = 4;
}
if (ballx + ballr > width || ballx - ballr < 0){
ballspdX = -ballspdX;
}
if (bally - ballr < 0){
ballspdY = -ballspdY;
}
if (ball_drop){
ballspdX = 0;
ballspdY = 1;
}
for (int i = 0; i < brickX.length; i ++){
for(int j = 0; j < brickY.length; j ++){
fill(red);
rect(brickX[i], brickY[j], brickW, brickH);
if (collideLineCircle(brickX[i], brickY[j] + brickH, brickX[i] + brickW, brickY[j] + brickH, ballx, bally, ballr)){
ballspdY = -ballspdY;
}
}
}
if (bally >= 800){
bally = 600;
ballx = 412.5;
ball_drop = true;
}
bally += ballspdY;
ballx += ballspdX;
}
boolean collideLineCircle(float x1, float y1, float x2, float y2, float cx, float cy, float cr){
float A = y2 - y1, B = x1 - x2, C = x2*y1 - x1+y2;
float denom = A+A + B*B;
if (denom == 0){
return dist(x1,y1, cx, cy) < cr;
}
float Ix = (B*B*cx-A*B*cy - A*C)/denom, Iy = (A*A*cy-A*B*cx - B*C)/denom;
if (Ix >= min(x1,x2) && Ix <= max(x1,x2) & Iy >= min(y1,y2) && Iy <= max(y1,y2)) {
return abs (A*cx + B*cy + C)/sqrt(denom) < cr;
}
float d1 = dist(x1,y1,cx,cy), d2 = dist(x2,y2,cx,cy);
return min(d1,d2) < cr;
}
void mouseMoved(MouseEvent evt){
paddleX = evt.getX();
}
There are a number of ways this can be done. Perhaps the simplest change, given the data structures you already have is to create another array, this time a boolean array, and call it something like brickIsVisible.
Then you can use a simple if statement, e.g., if (brickIsVisible[i]) in your loops to determine how to color the brick. The same variable can be used to tell whether or not to do a collision test between the ball and the brick.
As for the coloring itself, there are a couple options.
I'm not sure how you are drawing your board. If you redraw the entire board with each gameloop frame, then presumably you first draw the background (which covers over the bricks) and then you draw the bricks. If this what is happening, then if brickIsVisible[i] is false you can simply omit drawing that brick on top of the background.
Another technique that is sometimes used is to make use of a transparent color. This is done by adding an alpha channel value to the color definition. Thus there are four variables instead of three. They are referred to as RGBA instead of RGB. If the fourth variable is 0, the color will be transparent. If it is 255 it will be fully visible. Intermediate values in sequence can be used if you want to create a fade in or fade out.
I am guessing you are using java.awt.Color. Following is an example that uses the four argument constructor, with the fourth being the alpha channel.
Color invisiblePurple = new Color(255, 0, 255, 0);
If the color is invisible, the RGB values don't really matter.
These days I mostly use JavaFX for graphics, so I might not be up on all the tricks of the trade with AWT/Swing. With JavaFX, one can directly set an opacity property for a graphic being displayed, which is pretty convenient. I think part of the reason that this is available in JavaFX is that screen graphics are structured more like a DOM tree (like an HTML domain object model), and the redrawing is handled behind the scenes on the current state of the tree, rather than explicitly for each object, as it is with AWT/Swing.
Another possible technique shown below uses a brick class array. The class has a 'show' boolean associated with it and the bricks are only displayed when brick[id].show is true. In this demo when the brick is selected with a mouse brick[id].show is set to false and that brick is not displayed. For your project you would have to do this when a brick is hit by the ball.
/*
Creates a grid of rectangles from a Brick class array.
Syntax: brick[id] = new Brick( x, y, w, h, "title", bkgrndColor, txtColor);
ID is taken from position in array.
*/
final int _brickGridX = 40;
final int _brickGridY = 60;
final int _brickW = 120;
final int _brickH = 60;
color BLUE = color(64, 124, 188);
color LTGRAY = color(185, 180, 180);
color YELLOW = color(245, 250, 13);
color RED = color(255, 0, 0);
color BLACK = color(0, 0, 0);
color WHITE = color(255, 255, 255);
Brick[] brick;
class Brick {
float x, y, w, h;
String title;
color bkgrnd;
color txtColor;
boolean show;
// Constructor
Brick(int xpos, int ypos, float wt, float ht, String titleStr, color background, color foreground) {
x = xpos;
y = ypos;
w = wt;
h = ht;
title = titleStr;
bkgrnd = background;
txtColor = foreground;
}
void display(int id) {
if (brick[id].show) {
fill(bkgrnd); // background color
stroke(0);
rect(x, y, w, h);
fill(txtColor); // text color
textSize(42);
textAlign(CENTER, CENTER);
text(title, x, y, w, h);
}
}
void press(int id) {
println("brick id = ", id + ": show =", brick[id].show);
}
}
void brickGrid() {
int left = 0;
int top = 0;
int vg = 0; // Space between cols (vert.gutter)
int hg = 0; // Space between rows (horz.gutter)
int rows = 5;
int cols = 5;
int id = 0;
brick = new Brick[rows*cols]; // creates brick array
for (int k = 0; k < cols; k++) {
for (int j = 0; j < rows; j++) {
left = _brickGridX + j * (_brickW + vg);
top = _brickGridY + k * (_brickH + hg);
brick[id] = new Brick(left, top, _brickW, _brickH, str(id), LTGRAY, BLACK);
brick[id].show = true;
id++;
}
}
}
void setup() {
size(800, 600);
background(BLUE);
brickGrid();
}
void draw() {
background(BLUE);
for (int i = 0; i < brick.length; i++) {
brick[i].display(i);
}
}
void mousePressed() {
for (int i = 0; i < brick.length; i++) {
if ((mouseX >= brick[i].x) && (mouseX <= brick[i].x + _brickW) && (mouseY >= brick[i].y) && (mouseY <= brick[i].y + _brickH)) {
brick[i].show = false;
// brick[i].press(i);
}
}
}

Drag-resizing rectangle with fixed aspect ratio northwest corner

I have a Java app where the user can crop a subimage from its original self. The crop area is selected by drawing a rectangle over the original image. The rectangle can then be resized diagonally. And so far, everything works!
The user also has an option to lock the aspect ratio of the rectangle to 4:3. I can achieve this simply by setting the width to w = h / 4 * 3;
However, when it comes to resizing with locked ratio, the rectangle behaves strangely and is no longer stationary when dragging from the northwest corner (see gif below). Had the same problem with southwest corner, but that could be fixed by instead setting height to h = w / 3 * 4; but I can't figure out how to do this mathematically for the northwest corner. I have provided a copy-pastable demo for experimentation:
public class CropDemo {
public static void main(String[] args) {
CropPanel cropPanel = new CropPanel();
cropPanel.setPreferredSize(new Dimension(640, 480));
JFrame jFrame = new JFrame("Crop Panel");
jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jFrame.getContentPane().add(cropPanel);
jFrame.setResizable(false);
jFrame.pack();
jFrame.setLocationRelativeTo(null);
jFrame.setVisible(true);
}
}
class CropPanel extends JPanel {
private static final long serialVersionUID = 1L;
private boolean fixedRatio = true;
private Rectangle rectangle;
private Point clickPoint;
private static final int HOVERING = 0;
private static final int MOVING = 1;
private static final int RESIZING = 2;
public CropPanel() {
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
MouseAdapter mouseHandler = new MouseAdapter() {
private Point startPoint = null;
#Override
public void mouseClicked(MouseEvent e) {
if (rectangle != null && getCursorState() == HOVERING) {
rectangle = null;
repaint();
}
}
#Override
public void mousePressed(MouseEvent e) {
clickPoint = e.getPoint();
startPoint = e.getPoint();
}
#Override
public void mouseMoved(MouseEvent e) {
if (rectangle != null) {
Point mouse = e.getPoint();
int width = rectangle.x + rectangle.width;
int height = rectangle.y + rectangle.height;
final int off = 5;
if (mouse.x > rectangle.x - off && mouse.x < width + off && mouse.y > rectangle.y - off
&& mouse.y < height + off) {
if (mouse.x <= rectangle.x + off && mouse.y >= height - off) {
setCursor(Cursor.getPredefinedCursor(Cursor.SW_RESIZE_CURSOR));
} else if (mouse.x >= width - off && mouse.y >= height - off) {
setCursor(Cursor.getPredefinedCursor(Cursor.SE_RESIZE_CURSOR));
} else if (mouse.x <= rectangle.x + off && mouse.y <= rectangle.y + off) {
setCursor(Cursor.getPredefinedCursor(Cursor.NW_RESIZE_CURSOR));
} else if (mouse.x >= width - off && mouse.y <= rectangle.y + off) {
setCursor(Cursor.getPredefinedCursor(Cursor.NE_RESIZE_CURSOR));
} else {
setCursor(Cursor.getPredefinedCursor(Cursor.MOVE_CURSOR));
}
} else {
setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));
}
}
}
#Override
public void mouseDragged(MouseEvent e) {
if (clickPoint != null) {
Point mouse = e.getPoint();
if (getCursorState() == MOVING) {
int dx = rectangle.x + mouse.x - clickPoint.x;
int dy = rectangle.y + mouse.y - clickPoint.y;
rectangle.setLocation(dx, dy);
clickPoint = e.getPoint();
} else if (getCursorState() == RESIZING) {
int dx = mouse.x - startPoint.x;
int dy = mouse.y - startPoint.y;
int height = rectangle.height;
int width = rectangle.width;
int x = 0;
int y = 0;
int w = 0;
int h = 0;
switch (getCursor().getType()) {
case Cursor.SW_RESIZE_CURSOR:
x = mouse.x + dx;
y = rectangle.y;
w = width - dx;
h = height + dy;
if (fixedRatio) {
h = w / 3 * 4;
}
break;
case Cursor.SE_RESIZE_CURSOR:
x = rectangle.x;
y = rectangle.y;
w = width + dx;
h = height + dy;
if (fixedRatio) {
w = h / 4 * 3;
}
break;
case Cursor.NW_RESIZE_CURSOR:
x = mouse.x + dx;
y = mouse.y + dy;
w = width - dx;
h = height - dy;
// This is where I'm lost
// something else needs to be done
if (fixedRatio) {
w = h / 4 * 3;
}
break;
case Cursor.NE_RESIZE_CURSOR:
x = rectangle.x;
y = mouse.y + dy;
w = width + dx;
h = height - dy;
if (fixedRatio) {
w = h / 4 * 3;
}
break;
}
rectangle.setBounds(x, y, w, h);
startPoint = mouse;
} else {
int x = Math.min(clickPoint.x, mouse.x);
int y = Math.min(clickPoint.y, mouse.y);
int w = Math.max(clickPoint.x - mouse.x, mouse.x - clickPoint.x);
int h = Math.max(clickPoint.y - mouse.y, mouse.y - clickPoint.y);
if (rectangle == null) {
rectangle = new Rectangle(x, y, w, h);
} else {
rectangle.setBounds(x, y, w, h);
}
}
repaint();
}
}
};
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.DARK_GRAY);
g.fillRect(0, 0, getWidth(), getHeight());
Graphics2D graphics2D = (Graphics2D) g.create();
if (rectangle != null) {
Area fill = new Area(new Rectangle(new Point(0, 0), getSize()));
fill.subtract(new Area(rectangle));
if (clickPoint != null) {
graphics2D.setColor(new Color(0, 0, 0, 0));
} else {
graphics2D.setColor(new Color(0, 0, 0, 200));
}
int x = rectangle.x;
int y = rectangle.y;
int w = rectangle.width;
int h = rectangle.height;
graphics2D.fill(fill);
graphics2D.setColor(Color.WHITE);
graphics2D.setStroke(
new BasicStroke(1, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, new float[] { 6 }, 0));
graphics2D.drawRect(x, y, w, h);
if (w >= 30 && h >= 30) {
graphics2D.setStroke(new BasicStroke(3));
graphics2D.drawLine(x + 1, y + 1, x + 8, y + 1);
graphics2D.drawLine(x + 1, y + 1, x + 1, y + 8);
graphics2D.drawLine(x + w - 1, y + 1, x + w - 8, y + 1);
graphics2D.drawLine(x + w - 1, y + 1, x + w - 1, y + 8);
graphics2D.drawLine(x + 1, y + h - 1, x + 8, y + h - 1);
graphics2D.drawLine(x + 1, y + h - 1, x + 1, y + h - 8);
graphics2D.drawLine(x + w - 1, y + h - 1, x + w - 8, y + h - 1);
graphics2D.drawLine(x + w - 1, y + h - 1, x + w - 1, y + h - 8);
}
}
graphics2D.dispose();
g.dispose();
}
private int getCursorState() {
switch (getCursor().getType()) {
case Cursor.CROSSHAIR_CURSOR:
return HOVERING;
case Cursor.MOVE_CURSOR:
return MOVING;
case Cursor.SW_RESIZE_CURSOR:
case Cursor.SE_RESIZE_CURSOR:
case Cursor.NW_RESIZE_CURSOR:
case Cursor.NE_RESIZE_CURSOR:
case Cursor.N_RESIZE_CURSOR:
case Cursor.S_RESIZE_CURSOR:
case Cursor.W_RESIZE_CURSOR:
case Cursor.E_RESIZE_CURSOR:
return RESIZING;
default:
return -1;
}
}
}
Firstly just to note, the aspect ratio you are using is 3:4 not 4:3:
3:4 means that for every 3 units of width there are 4 units of height.
4:3 means that for every 4 units of width, there are 3 units of height.
w = h / 4 * 3 is calculating 3:4, not 4:3.
w = h / 3 * 4 or h = w / 4 * 3 calculates 4:3
Moving on to why your resizing breaks, when you create a Rectangle you provide the x, y coordinates of it's top left corner, and it's width and height:
Rectangle rectangle = new Rectangle(x, y, width, height)
The rectangle will then be drawn from x, y to x + width, y + height
The resizing part of your code works fine, when the mouse is dragged you update x, y, width, and height correctly.
The reason why applying the aspect ratio breaks it, is because you are updating width, and height, but you are not updating x and y.
Lets say the user performed a Northwest resize, and you now have a rectangle as follows:
x => 10
y => 10
width => 5
height => 10
You then apply your aspect ratio w = h / 4 * 3:
x => 10
y => 10
width => 8
height => 10
Because you are drawing from the top left corner, the rectangle has now grown from left to right, but you want it to grow from right to left. When you resize in the Northwest direction, you always want the bottom right corner of the rectangle to remain in the same place. The reason why this does not happen with your code is because when you apply the aspect ratio to the rectangle's width, you do not then update the start x, y point of the rectangle.
Using the above example, x and y should be updated as follows:
x => 7
y => 10
width => 8
height => 10
Here is a solution that I came up with:
else if (getCursorState() == RESIZING) {
Point startPoint = null;
Point endPoint = null;
switch(getCursor().getType()) {
case Cursor.SW_RESIZE_CURSOR:
startPoint = new Point((int) mouse.getX(), (int) rectangle.getMinY());
endPoint = new Point((int) rectangle.getMaxX(), (int) mouse.getY());
break;
case Cursor.NW_RESIZE_CURSOR:
startPoint = new Point((int) mouse.getX(), (int) mouse.getY());
endPoint = new Point((int) rectangle.getMaxX(), (int) rectangle.getMaxY());
break;
case Cursor.NE_RESIZE_CURSOR:
startPoint = new Point((int) rectangle.getMinX(), (int) mouse.getY());
endPoint = new Point((int) mouse.getX(), (int) rectangle.getMaxY());
break;
case Cursor.SE_RESIZE_CURSOR:
startPoint = new Point((int) rectangle.getMinX(), (int) rectangle.getMinY());
endPoint = new Point((int) mouse.getX(), (int) mouse.getY());
break;
}
rectangle.setFrameFromDiagonal(startPoint, endPoint);
if (fixedRatio) {
// Calculate 3:4 aspect ratio
rectangle.height = rectangle.width / 3 * 4;
// If this is a NW or NE resize, we need to adjust the start y coordinate to account for the new height
// This keeps the bottom right corner in the same place for a NW resize
// and the bottom left corner in the same place for a NE resize
if (getCursor().getType() == Cursor.NW_RESIZE_CURSOR || getCursor().getType() == Cursor.NE_RESIZE_CURSOR) {
rectangle.y = endPoint.y - rectangle.height;
}
}
}
So when the rectangle is resized in the Northwest or Northeast directions, and the aspect ratio is applied, I also update the rectangle's start y coordinate to account for the change in height.

Java OpenCV Layer small image onto larger image with transparency

I am trying to write a function that overlays an image at a rectangle with transparency over top of another image, However it doesn't layer the images it just erases the section that I overlay and the transparency cuts through the entire image. Here is my code.
public static void overlayImage(String imagePath, String overlayPath, int x, int y, int width, int height) {
Mat overlay = Imgcodecs.imread(overlayPath, Imgcodecs.IMREAD_UNCHANGED);
Mat image = Imgcodecs.imread(imagePath, Imgcodecs.IMREAD_UNCHANGED);
Rectangle rect = new Rectangle(x, y, width, height);
Imgproc.resize(overlay, overlay, rect.size());
Mat submat = image.submat(new Rect(rect.x, rect.y, overlay.cols(), overlay.rows()));
overlay.copyTo(submat);
Imgcodecs.imwrite(imagePath, image);
}
EDIT: Here are some example pictures:
Before:
After:
Found this function that does exactly what I needed.
public static void overlayImage(Mat background,Mat foreground,Mat output, Point location){
background.copyTo(output);
for(int y = (int) Math.max(location.y , 0); y < background.rows(); ++y){
int fY = (int) (y - location.y);
if(fY >= foreground.rows())
break;
for(int x = (int) Math.max(location.x, 0); x < background.cols(); ++x){
int fX = (int) (x - location.x);
if(fX >= foreground.cols()){
break;
}
double opacity;
double[] finalPixelValue = new double[4];
opacity = foreground.get(fY , fX)[3];
finalPixelValue[0] = background.get(y, x)[0];
finalPixelValue[1] = background.get(y, x)[1];
finalPixelValue[2] = background.get(y, x)[2];
finalPixelValue[3] = background.get(y, x)[3];
for(int c = 0; c < output.channels(); ++c){
if(opacity > 0){
double foregroundPx = foreground.get(fY, fX)[c];
double backgroundPx = background.get(y, x)[c];
float fOpacity = (float) (opacity / 255);
finalPixelValue[c] = ((backgroundPx * ( 1.0 - fOpacity)) + (foregroundPx * fOpacity));
if(c==3){
finalPixelValue[c] = foreground.get(fY,fX)[3];
}
}
}
output.put(y, x,finalPixelValue);
}
}
}

How to use different fill colour for specific rectangles

Based on the code I've used for my canvas drawing and the screenshot regarding that, I'm trying to fill a specific rectangle with a different colour but instead this unexpected behaviour occurs where other rectangles change stroke colour also. Does anyone know what can be done fix this issue?
I only want the 2nd rectangle from the the left on the top row to be filled black & stroked red whilst the other rectangles remain with a red stroke
public class Car extends View {
public Car(Context context) {
super(context);
init();
}
public Car(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public Car(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
Paint paint;
private void init() {
paint = new Paint();
paint.setColor(Color.RED);
paint.setStrokeWidth(4);
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int w = canvas.getWidth();
int h = canvas.getHeight();
int rectWidth = w / 5;
int space = w / 15;
int topRectHeight = getPaddingTop();
int bottomRectHeight = getPaddingBottom();
paint.setStyle(Paint.Style.STROKE); //add this
for (int i = 0; i < 4; i++) {
int left = i * (rectWidth + space);
int right = left + rectWidth;
if (i == 1){
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLACK);
}
else{
paint.setColor(Color.RED);
}
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, paint);
paint.setStyle(Paint.Style.STROKE);//add this
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, paint);
}
}
}
I only want the 2nd rectangle from the the left on the top row to be
filled black & stroked red whilst the other rectangles remain with a
red stroke
For this in the if Case when i=1 you need to do two things
setStyle to fill and setColor to black and draw the rectangle.
Then again set back the setStyle to stroke and setColor to red and draw rect2 of yours.
Code:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
int w = canvas.getWidth();
int h = canvas.getHeight();
int rectWidth = w / 5;
int space = w / 15;
int topRectHeight = getPaddingTop();
int bottomRectHeight = getPaddingBottom();
paint.setStyle(Paint.Style.STROKE); //add this
for (int i = 0; i < 4; i++) {
int left = i * (rectWidth + space);
int right = left + rectWidth;
if (i == 1){
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLACK);
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, paint);
//again set back the style here
paint.setStyle(Paint.Style.STROKE);
paint.setColor(Color.RED);
Rect rect2 = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect2, paint);
//this will draw the lower rectangle! Using extra variable rect3 just for safer side.
Rect rect3 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect3, paint);
}else{
Rect rect = new Rect(left, 0, right, topRectHeight);
canvas.drawRect(rect, paint);
paint.setStyle(Paint.Style.STROKE);//add this
Rect rect2 = new Rect(left, h - bottomRectHeight, right, h);
canvas.drawRect(rect2, paint);
}
}
}

Rotating Wheel with rotating icons

Now these days i am working on Rotating wheel likely attached screenshot.
I've found code from github https://github.com/R4md4c/AndroidRotaryWheelView
The difficulty is that i am not able to keep icons in vertical position during rotation of the wheel. Icons being rotated in form of its Wheel's Segment While it is required to keep them in vertical position as they are being displayed initially (as per screenshot-1).
I have to customize the following code where i need to change the Bounds for particular drawable's rect.
I find myself unable to achieve the exact calculation in the reference.
Any help would be highly appreciated.
#Override
public void onDraw(Canvas canvas) {
// set the height of Wheel childs items
canvas.scale(getWidth() / mViewRect.width(), getHeight() / 2
/ mViewRect.width(), xPosition, yPosition);
canvas.save(Canvas.MATRIX_SAVE_FLAG); // Saving the canvas and later
// restoring it so only this
// image will be rotated.
canvas.rotate((float) mRotationAngle, xPosition, yPosition);
for (int i = 0; i < mWedges.length; i++) {
Wedge f = mWedges[i];
mPaint.setColor(SEGMENT_COLOR);
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
canvas.drawPath(f, mPaint);
Rect rf = iconRect[i];
if ((mMenuEntries.get(i).getIcon() != 0)
&& (mMenuEntries.get(i).getLabel() != null)) {
System.out.println("the canvasd drawn ........");
// This will look for a "new line" and split into multiple lines
String menuItemName = mMenuEntries.get(i).getLabel();
String[] stringArray = menuItemName.split("\n");
mPaint.setColor(textColor);
mPaint.setStyle(Paint.Style.FILL);
// mPaint.setTextSize(textSize);
Rect rect = new Rect();
float textHeight = 0;
for (int j = 0; j < stringArray.length; j++) {
mPaint.getTextBounds(stringArray[j], 0,
stringArray[j].length(), rect);
textHeight = textHeight + (rect.height() + 3);
}
Rect rf2 = new Rect();
rf2.set(rf.left, rf.top - ((int) textHeight / 2), rf.right,
rf.bottom - ((int) textHeight / 2));
float textBottom = rf2.bottom;
for (int j = 0; j < stringArray.length; j++) {
mPaint.getTextBounds(stringArray[j], 0,
stringArray[j].length(), rect);
float textLeft = rf.centerX() - rect.width() / 2;
textBottom = textBottom + (rect.height() + 3);
mPaint.setTextSize(scalePX(8));
canvas.drawText(stringArray[j], textLeft - rect.left,
textBottom - rect.bottom, mPaint);
}
// canvas.rotate((float)mRotationAngle,
// rf.top-((int)textHeight/2), rf.bottom-((int)textHeight/2));
int index = checkSelection(canvas);
rf2 = rotaionRf(rf2, mRotationAngle);
if (i == index) {
// Puts in the Icon
Drawable drawable = getResources().getDrawable(
mMenuEntries.get(i).getIconSelected());
drawable.setBounds(rf2);
drawable.draw(canvas);
} else {
// Puts in the Icon
Drawable drawable = getResources().getDrawable(
mMenuEntries.get(i).getIcon());
drawable.setBounds(rf2);
drawable.draw(canvas);
}
// Icon Only
} else if (mMenuEntries.get(i).getIcon() != 0) {
System.out.println("the canvasd drawn ELSE........");
// Puts in the Icon
Drawable drawable = getResources().getDrawable(
mMenuEntries.get(i).getIconSelected());
drawable.setBounds(rf);
drawable.draw(canvas);
// Text Only
} else {
// Puts in the Text if no Icon
mPaint.setColor(this.textColor);
/*
* if (f != enabled && Wedge2Shown == true) {
* mPaint.setAlpha(disabledAlpha); } else {
* mPaint.setAlpha(textAlpha); }
*/
// mPaint.setAlpha(textAlpha);
mPaint.setStyle(Paint.Style.FILL);
// mPaint.setTextSize(textSize);
// This will look for a "new line" and split into multiple lines
String menuItemName = mMenuEntries.get(i).getLabel();
String[] stringArray = menuItemName.split("\n");
// gets total height
Rect rect = new Rect();
float textHeight = 0;
for (int j = 0; j < stringArray.length; j++) {
mPaint.getTextBounds(stringArray[j], 0,
stringArray[j].length(), rect);
textHeight = textHeight + (rect.height() + 3);
}
float textBottom = rf.centerY() - (textHeight / 2);
for (int j = 0; j < stringArray.length; j++) {
mPaint.getTextBounds(stringArray[j], 0,
stringArray[j].length(), rect);
float textLeft = rf.centerX() - rect.width() / 2;
textBottom = textBottom + (rect.height() + 3);
canvas.drawText(stringArray[j], textLeft - rect.left,
textBottom - rect.bottom, mPaint);
}
// canvas.drawTextOnPath(text, path, hOffset, vOffset, paint)
// canvas.rotate((float)mRotationAngle, xPosition, yPosition );
// canvas.drawRect(rf, mPaint);
}
// canvas.restore();
}
// canvas.restore();
canvas.restore();
// System.out.println()
canvas.save();
canvas.restore();
mPaint.setShader(mShader);
// mPaint.setAlpha(0x66);
// Draw the Selection Segment
if (mSelectionWedge != null) {
canvas.drawPath(mSelectionWedge, mPaint);
// canvas.drawRect(mSelectionWedge.getWedgeRegion().getBounds(),
// mPaint);
}
mPaint.setShader(null);
int index = checkSelection(canvas);
System.out.println("the index=====" + index);
if (checkSelection(canvas) != -1) {
}
}
on using canvas.rotate u have to make sure the x&y values u give it are the MAIN wheel center.

Categories