I am trying to draw 5 (for example) rectangles on canvas, using GC.drawRectangle(int x, int y, int width, int height);
After forth column rectangle should be drawn in next row as shown in the picture.Picture, layout for the rectangles drawn. I am not able to find some logic to draw rectangles as desired.
Here is what I was trying to do.
int col = (brushPanz-1) / 4;//gives column
int row = (brushPanz-1) % 4;//gives rows
for (int i = 0; i < brushPanz; i++) {
GC.drawRectangle((i * 172 + 5), col * 78 + 5, 500 / ratio, 220 / ratio);
}
Basically I want to use only one for loop to draw any number of rectangles. Someone, please help.
Without trying to debug your position offsets versus your size, you need (a) to compute a new row/col for each rect, (b) to use those computed values to position your rect and (c) to correctly compute row vs. column.
for (int i = 0; i < brushPanz; i++) {
int col = i % 4;//gives column
int row = i / 4;//gives rows
GC.drawRectangle((col * 172 + 5), row * 78 + 5, 500 / ratio, 220 / ratio);
}
Related
So I managed to get an image to rotate 90 degrees by using my code for 180 and messing about basically but Im still very confused on what the code actually does and how it does it. I understand the rotate 180 but not the rotate 90 with the code below. Can any explain this to me?
OFImage image1 = new OFImage(image);
for (int x = 0; x < image.getWidth(); ++x) {
for (int y = 0; y < image.getHeight(); ++y) {
image.setPixel(y, x, image1.getPixel(image.getWidth() - x - 1, y));
I have commented your code
OFImage image1 = new OFImage(image); // create a copy of `image`
for (int x = 0; x < image.getWidth(); ++x) { // loop through each column of pixels in original presumably from left to right
for (int y = 0; y < image.getHeight(); ++y) { // loop through each cell of the column presumably from top to bottom
image.setPixel(y, x, image1.getPixel(image.getWidth() - x - 1, y)); // here you have swapped the x and y coordinates and you are putting in the pixel from the copy that is at width - x - 1, y
So when x = 0 (column) and y = 0 (row), you are putting in a copy of the pixel from (W= image.width - 1, y) (last pixel in first row) into (0,0) so (W,0) => (0,0)
Then when x = 0 and y = 1 it is (W, 1) => (1, 0), then (W, 2) => (2, 0)
At the start of your loops, you are reading from the rightmost column, and writing to the topmost row.
Not sure how to describe the process in detail to be honest, but it's just using maths (obviously), to swap each pixel individually with the appropriate alternative pixel, to give the effect of a 90 degree rotation.
To help me understand it, I drew 3x3 and 4x4 grids, and labelled each cell, simulating pixels. And simply used the method "setPixel" with its parameters as an equation, and passed each pixel/co-ordinate through it to work out the result. I'd suggest doing the same, since it's probably the best method to understanding how the method works properly.
I have a JFrame that contains a custom JComponent that displays a grid with a fix amount of rows and columns. When the JFrame is resized, the spacing between lines is recalculated so that the grid increases in size while still keeping the same amount of elements. The issue comes when resizing to a height or width that is to large to fit n columns (or rows) but too small to fit n+1. Here's the correct view:
You can see the blue lines perfectly align with the black line on the right. If I increase the width of the window, I get the following problem:
The grid extends JComponent, and in its paintComponent I do the following:
// Get the size of the JFrame containing the Grid
Dimension df = getParent().getSize();
// Calculate spacing between vertical lines (20 = number of vertical lines)
int vert_spacing = (df.width - 2 * this.margin) / 20;
// Draw the black border
g.setColor(Color.BLACK);
g.drawRect(this.margin, this.margin, df.width - 2 * this.margin, df.height - 2 * this.margin);
// Draw vertical lines
for (int i = this.margin; i <= df.width - this.margin; i += vert_spacing) {
g.setColor(Color.blue);
g.drawLine(i, this.margin, i, df.height - this.margin);
}
A solution I thought of would be to "snap" to a good value after the JFrame is resized, but I haven't been able to get that to work and I'm not sure if it's the best solution. The issue is with the fact that drawLine takes ints as its values so the spacing between lines gets rounded up/down. Is there a workaround for this?
Thanks!
I think the problem is that you are painting the rectangle too large. You need to take into account that the rectangle size should be based on the vertical spacing * 20 and not the actual size of the parent window.
Maybe something like:
int vert_spacing = (df.width - 2 * this.margin) / 20;
int extraSpace = df.width - (vert_spacing * 20);
// Draw the black border
g.setColor(Color.BLACK);
g.drawRect(this.margin, this.margin, (df.width - extraSpace) - 2 * this.margin, df.height - 2 * this.margin);
Now of course the above solution will be skewed to the left so you may also want to center your grid in the space available. So in addition to using your margin as the X offset you would need to use half of the extra space:
int vert_spacing = (df.width - 2 * this.margin) / 20;
int extraSpace = df.width - (vert_spacing * 20);
int xOffset = extraSpace / 2;
// Draw the black border
g.setColor(Color.BLACK);
g.drawRect(this.margin + xOffset, this.margin, (df.width - extraSpace) - 2 * this.margin, df.height - 2 * this.margin);
Of course you would also need to use the xOffset when drawing the vertical lines.
You should work with floating coordinates and then round them just in order to get the integers required by the "draw" function:
// Calculate spacing between vertical lines (20 = number of vertical lines)
float vert_spacing = (float)(df.width - 2 * this.margin) / 20f;
// Draw vertical lines
for (int i=0; i<20; i++) {
int x = Math.round(this.margin + i*vert_spacing);
g.setColor(Color.blue);
g.drawLine(x, this.margin, x, df.height - this.margin);
}
// load pixels into an image
this.image = new BufferedImage(this.width,
this.height,
BufferedImage.TYPE_INT_RGB);
// get actual image data for easier pixel loading
byte[] iData = new byte[this.size - 54];
for(int i = 0; i < this.size - 54; i++) {
iData[i] = this.data[i+54];
}
// start from bottom row
for(int y = this.height-1; y >= 0; y--) {
for(int x = 0; x < this.width; x++) {
int index = (this.width*y + x) * 3;
int b = iData[index];
int g = iData[index+1];
int r = iData[index+2];
//System.out.format("R: %s\nG: %s\nB: %s\n\n", r, g, b);
// merge rgb values to single int
int rgb = ((r&0x0ff)<<16)|((g&0x0ff)<<8)|(b&0x0ff);
// build image from bottom up
this.image.setRGB(x, this.height-1-y, rgb);
}
}
I'm reading RGB values from a Bitmap. My iData byte array is correct, as I've checked it against a hex editor. However, when I run this loop, my output image is warped (see picture). I've been wracking my brain for hours trying to fix this, why is it happening?
Input image is a canadian flag.
output image:
I wasn't accounting for the zero-byte padding on the width, for which the formula is
WidthWithPadding = ceiling((w*colorDepth)/32)*32.
Images usually have width, depth (bits per pixel), and stride. Usually the stride is not just width*depth, but padded by some amount (often used to align each row to a 16-bit boundary for memory access reasons).
Your code does not appear to be accounting for the stride or any padding, which explains the offset as you go through the image. I'm surprised the colors don't get switched (suggesting the padding is the same size as a pixel), but those undefined values are causing the black stripe through the image.
Rather than multiplying (this.width*y + x) * 3 to get your index, you should use (this.stride*y + x) * 3 with the appropriate value for stride. The BufferedImage class doesn't seem to provide that in any obvious fashion, so you need to calculate or fetch that otherwise.
The general issue that's happening is that your code has conflated stride (distance between rows in bytes) with width (number of bytes in a row); in aligned data formats these are not necessarily the same thing. The general result of this is getting the sort of skew you're seeing, as the second row starts out on the last byte(s) of the first row, the third row starts out on the second-to-last byte(s) of the second row, and so on.
The first thing you need to do is calculate the stride of the data, and use that as the multiplication factor for the row. Here is a simplified loop that also is somewhat more efficient than multiplying on a per-pixel basis:
int stride = (this.width + 3) & ~3; // rounds up to the nearest multiple of 4
for (int y = 0; y < this.height; y++) {
int idx = y*stride;
for (int x = 0; x < this.width; x++) {
int b = iData[idx++];
int g = iData[idx++];
int a = iData[idx++];
// etc.
}
}
Note that the rounding trick above ((w + a - 1) & ~(a - 1)) only works for power-of-two values; a more general form of the rounding trick is:
int stride = (width + stride - 1)/stride*stride;
although it's very uncommon to find alignments that aren't a power of 2 in the first place.
I need to draw random shapes on a grid such as lines squares etc. This part I'm able to do. My problem is the start and end point of the lines I'm drawing falls anywhere in a grid cell. I would like them to be only at intersection points. One cell in the grid is a 10x10 pixel grid. Do i have to write an algorithm to assign the pixel to its nearest intersection point on the grid or is there a easier way. I'm using a buffered image to draw the grid. Please Help. this is what i have so far
for (int i = 0; i < 61; i++) {
g2d.drawLine((imgDim.width + 2) / 40 * i, 0,
(imgDim.width + 2) / 40 * i, imgDim.height - 1);
g2d.drawLine(0, (imgDim.height + 2) / 60 * i,
imgDim.width - 1, (imgDim.height + 2) / 60 * i);
}
Thank you
How are you coming up with the random points? Making an adjustment there might be the easiest way. That is, just drop a 0 in the process you are using to come up with the points in the first place. Then when you are ready to draw it, add a 0 back.
Seriously? In order to make a random point (pixelX, pixelY) snap to the closest point of a grid.
int gridSize = 10;
int x = (pixelX + gridSize / 2) / gridSize * gridSize;
int y = (pixelY + gridSize / 2) / gridSize * gridSize;
I would like to implement a "grid view" of pixmaps. This is how I would like the UI to behave: You click a button and it shows a QGraphicsView with a QGraphicsScene (done) and then I would like to show all of my QPixmaps in a grid view. I don't actually want to see a grid I just want to organize the pixmaps like 10 columns (pixmaps) pr. row, and then a 10px whitespace in-between each pixmap. (not done). How would this be implemented?
EDIT: Here's what I've done so far (which produces the outcome described in the second comment)
public SpriteScene() {
super(0, 0, 800, 500);
QPixmap[] sprites = GUI.getWInterface().sprites;
List<QPixmap> l = Arrays.asList(sprites);
Iterator<QPixmap> i = l.iterator();
int rows = 10 / sprites.length;
boolean isDone = false;
for(int y = 0; y < rows; y++) {
for(int x = 0; x < 10; x++) {
if(i.hasNext()) {
QGraphicsPixmapItem pixmap = addPixmap(i.next());
pixmap.setPos(x * 64 + 10 , y * 64 + 10);
} else {
isDone = true;
break;
}
}
if(isDone) {
break;
}
}
}
SpriteScene extends QGraphicsScene and is being added to a QGraphicsView like this:
spriteView = new QGraphicsView(new SpriteScene(), this);
spriteView.setGeometry(0, 35, 850, 550);
spriteView.setAlignment(new Qt.AlignmentFlag[]{Qt.AlignmentFlag.AlignLeft, Qt.AlignmentFlag.AlignTop});
spriteView.hide();
Oh and by the way each pixmap is 64x64px :)
pixmap.setPos(x * 64 + 10 , y * 64 + 10);
Write that down on paper for the first few values:
x = 0, y = 0 => pos = ( 10, 10)
x = 1, y = 0 => pos = ( 74, 10)
x = 2, y = 0 => pos = (138, 10)
There's only 64 pixel different between each successive x offset. You need 74 pixels - the size of the pixmap plus the size of the border.
Set a few variables for your image with, height, horizontal and vertical spacing, and your code should look like:
pixmap.setPos(x * (width+hspacing) + offsetx, y * (height+vspacing) + offsety);
The offsetx/y would probably look nicer if they were half the respective spacing valued to get the grid "centered".