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".
Related
The assignment is to draw chips on a supposed cookie at random points while counting each chip and storing the coordinates so that each chip doesn't move. Each chip should be a different color and initiated on a mouse press.
I've tried to put the coordinates into an array, multiple arrays a single array list and tried to use if and for loops. The results before were that it would generate a single chip of a different colour each click (sort of because sometimes the random number generated is outside of my specified range). After using and looping through multiple array lists the current behaviour is that it generates a grid and the count is exponentially growing with each click, some points have a lot of overlap and the chips in the grid all ave one colour i.e. The last to be assigned
//Put graphics code here
public void draw(Graphics g){
ArrayList coordinates = new ArrayList();
col1= generator.nextInt(256) + 0;
col2= generator.nextInt(256) + 0;
col3= generator.nextInt(256) + 0;
canvasMaxWidth=800;
canvasMaxHeight=600;
canvasMinWidth=400;
canvasMinHeight=200;
int newX = (int) (Math.random() * canvasMaxWidth) + canvasMinWidth;
int newY = (int) (Math.random() * canvasMaxHeight) + canvasMinHeight;
Point point = new Point(newX, newY);
g.setColor(new Color(205,133,63));
g.fillOval(canvasMinWidth,canvasMinHeight,400,400);
for(Point point : coordinates){
if(point.y > 249 && point.y < 549 && point.x > 449 && point.x < 749){
g.setColor(new Color(col1, col2, col3));
g.fillOval(point.x, point.y, 7, 7);
}
}
g.setColor(Color.black);
g.drawString("Number of Sprinkles: "+ count, 100, 80);
}
//Code to respond to a mouse press
public void mousePressed(MouseEvent mouse){
}
The expected result is essentially a speckled disk that counts each speckle on the disk with each speckle not moving.
At present it appears that no point is moving but there's not a lot of randomness to what is happening. the speckles multiply each click vs iterate and form a grid.
ArrayList<Point> coordinates = new ArrayList<Point>();
is much easier to track coordinates rather than using two separate lists. Everything is happening in a grid format because you are using a nested for loop for i and j.
You are currently performing:
if i = 0, 1, 2 and j = 0 , 1, 2
i j
0 0
0 1
0 2
1 0
1 1
1 2
2 0
2 1
2 2
so you can see where the grid-like layout is coming from. Using a Point object, you could instead do:
for(Point point : coordinates){
if(point.y > 249 && point.y < 549 && point.x > 449 && point.x < 749){
g.setColor(new Color(col1, col2, col3);
g.fillOval(point.x, point.y, 7, 7);
}
}
I'm unsure why you are using a counter, as it would be performing for the length of the coordinates. If you would like to add randomness, then you can dynamically create values using the Random class.
int colorValue = (int) (Math.random() * 255);
and if you wanted to perform random positions, you could randomly generate them through:
int newX = (int) (Math.random() * (canvasMaxWidth - canvasMinWidth)) + canvasMinWidth;
int newY = (int) (Math.random() * (canvasMaxHeight - canvasMinHeight)) + canvasMinHeight;
Point point = new Point(newX, newY);
Edit with your code:
int newX = (int) (Math.random() * (canvasMaxWidth - canvasMinWidth)) + canvasMinWidth;
int newY = (int) (Math.random() * (canvasMaxHeight - canvasMinHeight)) + canvasMinHeight;
Point point = new Point(newX, newY);
coordinates.add(point);
counter++;
redList.add((int) (Math.random() * 255));
greenList.add((int) (Math.random() * 255));
blueList.add((int) (Math.random() * 255));
g.setColor(new Color(205,133,63));
g.fillOval(canvasMinWidth,canvasMinHeight,400,400);
for(int z = 0; z < coordinates.size(); z++){
if(coordinates.get(z).y > 249 && coordinates.get(z).y < 549 && coordinates.get(z).x > 449 && coordinates.get(z).x < 749){
g.setColor(new Color(redList.get(z).intValue(), greenList.get(z).intValue(), blueList.get(z).intValue()));
g.fillOval(coordinates.get(z).x, coordinates.get(z).y, 7, 7);
}
}
Edit #2: here is a sample of how you would have the static variables
public class myClass{
static ArrayList<Point> coordinates = new ArrayList<Point>();
static ArrayList<Integer> redList = new ArrayList<Integer>();
static ArrayList<Integer> greenList = new ArrayList<Integer>();
static ArrayList<Integer> blueList = new ArrayList<Integer>();
static int counter = 0;
Let's say that I have an image like this one (in reality, I have a lot of them, but let's keep it simple)
example picture and I'd like to replace background color (that's the one that's not roads) with green color.
To do that I'd have to iterate through all of the pixels in the map and replace ones that match the color I want to remove.
But as you might think, my image is not a simple as 256x256 picture, but it's slightly bigger, it's 1440p, and the performance drop is significant.
How would I replace all of the unwanted pixels without iterating through all of the pixels.
I'm working with Processing 3 - Java(Android) and I'm currently using this piece of code:
for (x = 0; x < img.width; x++){
for (int y = 0; y < img.height; y++) {
//Color to transparent
int index = x + img.width * y;
if (img.pixels[index] == -1382175 || img.pixels[index] == 14605278 || img.pixels[index] == 16250871) {
img.pixels[index] = color(0, 0, 0, 0);
} else {
img.pixels[index] = color(map(bright, 0, 255, 64, 192));
}
}
}
Solved it with this one:
private PImage swapPixelColor(PImage img, int old, int now) {
old &= ~0x00000000;
now &= ~0x00000000;
img.loadPixels();
int p[] = img.pixels, i = p.length;
while (i-- != 0) if ((p[i]) == old) p[i] = now;
img.updatePixels();
return img;
}
It works like a charm and it takes almost no time:
Swapped colors in 140ms // That's replacing it three times(different colors ofc)
This is a follow-up post to my previous question, here. I got a remarkable response to instead of using array data tracking, to use matrixes. Now, the code here works just as planned (as in, the rectangles somewhat most of the time get filled in properly with white), but it's very inconsistent. When holding the left or right mouse button the colors phase over each other in a battle of randomness, and I don't know nearly that much about why this is happening. Just for reference, I'm using Java in Processing 3.
This is a result that I made with the project. As you can see, it looks fine.
Except for that jitter when hovering over a rect, and that more than not the rectangles are not being filled in half the time. And plus, the hover color is cycling almost randomly.
int cols, rows;
int scl = 20;
boolean[][] matrix = new boolean[scl+1][scl+1];
void setup() {
size(400, 400);
int w = 400;
int h = 400;
cols = w / scl;
rows = h / scl;
}
void draw() {
background(255);
for (int x = 0; x < cols; x++) {
for (int y = 0; y < rows; y++) {
int xpos = x*scl;
int ypos = y*scl;
stroke(55);
if ((mouseX >= xpos && mouseX <= xpos+scl) &&
(mouseY >= ypos && mouseY <= ypos+scl)) {
fill(75);
if (mousePressed == true) {
println("Clicked at: " + xpos + " and " + ypos);
if (!matrix[xpos/scl][ypos/scl]) {
matrix[xpos/scl][ypos/scl] = true;
} else {
matrix[xpos/scl][ypos/scl] = false;
}
fill(100);
//here is the desired location for the fill to remain constant even
//after unclicking and leaving hover
}
println("Mouse at: " + xpos + " and " + ypos);
} else {
fill(50);
}
if (matrix[x][y]) {
//fill(204, 102, 0);
fill(240);
rect(xpos, ypos, scl, scl);
}
rect(xpos, ypos, scl, scl);
}
}
}
Remeber that Processing fires the draw() function 60 times per second.
So your check for whether the mouse is pressed is happening 60 times per second. That means you're toggling the state of whatever cell the mouse is in 60 times per second.
To fix that problem, you might switch to using the event functions like mousePressed() instead of constantly polling every frame.
From the reference:
int value = 0;
void draw() {
fill(value);
rect(25, 25, 50, 50);
}
void mousePressed() {
if (value == 0) {
value = 255;
} else {
value = 0;
}
}
As for certain cells being skipped over, that's because when you move the mouse, it doesn't actually go through every pixel. It "jumps" from frame to frame. Those jumps are usually small enough that humans don't notice it, but they're large enough that it's skipping over cells.
One solution to this is to use the pmouseX and pmouseY variables to calculate a line from the previous mouse position to the current mouse position, and fill in any cells that would have been hit along the way.
I am currently making a program to procedurally generate 2d terrain maps, with different technics such as perlin noise, simplex, voronoi, fractal noise, etc. on a size-defined image to be able to use it in my games requiring a 2d terrain.
I've come across the "Modelling fake planets" section of http://paulbourke.net/fractals/noise and I need to make it on a 2d texture, and not on a 3d world like it is explained.
Now I'm trying to
create a line from point 'X' to point 'Y'
That line will define a zone with a boolean value for left or right of the line to be "darker".
Doing that for a number of iteration to create a texture.
Using the RGB value of the final image to change stuffs such as forests, lakes, etc.
this would work this way:
overrides with this method below,
http://img35.imageshack.us/img35/24/islf.png
I used my high school maths powers to create a code sample but it's not really working...
Questions:
How should i change it so it works instead of just being failing?
Is there a simpler way than using what i am using?
Java file:
if i need an example on how i will proceed, here it is:
package Generator;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.util.Random;
import VectorialStuffs.Vector2;
public class Linear
{
public static BufferedImage generateImage(Dimension dim, int iterations)
{
BufferedImage image = new BufferedImage(dim.width, dim.height, BufferedImage.TYPE_INT_ARGB);
//point X and point Y
Vector2 pointX;
Vector2 pointY;
//difference between those
Vector2 diff;
Vector2 side;
double slope;
//random
Random rand = new Random();
boolean direction; //the orientation of the dark zone. (left/right)
for (int i = 0; i < iterations; ++i)
{
pointX = new Vector2(0, 0);
pointY = new Vector2(0, 0);
direction = rand.nextBoolean();
System.out.println(direction);
side = new Vector2(0, 0); //there are 4 sides of the image.
while (side.x == side.y)
{
side.x = rand.nextInt(3); //0 - 1 - 2 - 3
side.y = rand.nextInt(3);
}
switch(side.x) //not the x coord, the X point! ;D
{
//x = random and y = 0
case 0:
pointX.x = rand.nextInt(dim.width);
pointX.y = 0;
break;
//x = max and y = random
case 2:
pointX.x = dim.width;
pointX.y = rand.nextInt(dim.height);
break;
//x = random and y = max
case 1:
pointX.x = rand.nextInt(dim.width);
pointX.y = dim.height;
break;
//x = 0 and y = random
case 3:
pointX.x = 0;
pointX.y = rand.nextInt(dim.height);
break;
}
switch(side.y) //not the y coord, the Y point! ;D
{
//x = random and y = 0
case 0:
pointY.x = rand.nextInt(dim.width);
pointY.y = 0;
break;
//x = max and y = random
case 2:
pointY.x = dim.width;
pointY.y = rand.nextInt(dim.height);
break;
//x = random and y = max
case 1:
pointY.x = rand.nextInt(dim.width);
pointY.y = dim.height;
break;
//x = 0 and y = random
case 3:
pointY.x = 0;
pointY.y = rand.nextInt(dim.height);
break;
}
diff = new Vector2((pointY.x - pointX.x), (pointY.y - pointX.y));
slope = diff.y / diff.x;
Graphics graph = image.getGraphics();
if (direction) //true = right | false = left
{
int start; //the start x coordinate, on the line then increases until reaching the end of the image
int end = dim.width;
graph.setColor(Color.red);
graph.fillRect(pointX.x - 8, pointX.y -8, 16, 16);
graph.setColor(Color.yellow);
graph.fillRect(pointY.x - 8, pointY.y -8, 16, 16);
for (int times = 0; times < dim.height; ++times) //horizontal drawer
{
System.out.println(times);
start = (int)((times-diff.y)/slope + diff.y); //this is where it goes wrong?
for (int value = start; value < end; ++value)
{
graph.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255), 100));
graph.fillRect(value, times, 1, 1);
}
}
graph.dispose();
}
else
{
int start; //the start x coordinate, on the line then increases until reaching the end of the image
int end = dim.width;
graph.setColor(Color.red);
graph.fillRect(pointX.x - 8, pointX.y -8, 16, 16);
graph.setColor(Color.yellow);
graph.fillRect(pointY.x - 8, pointY.y -8, 16, 16);
for (int times = 0; times < dim.height; ++times) //horizontal drawer
{
System.out.println(times);
start = (int)((times-diff.y)/slope);
for (int value = end; value < start; --value)
{
graph.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255), 100));
graph.fillRect(value, times, 1, 1);
}
}
graph.dispose();
}
}
return image;
}
}
Note:
In this case vector2 is just a class with X and Y, which can be accessed (this is probably going to be temporary).
Startup part to avoid you losing time:
terrainImage = Linear.generateImage(size, 1); //size being a Dimension. -> "new Dimension(256, 256)"
if (terrainImage != null)
{
Icon wIcon = new ImageIcon(terrainImage);
JOptionPane.showMessageDialog(null, "message", "title", JOptionPane.OK_OPTION, wIcon);
}
//edit
here is the code that needs improvement:
if (direction) //true = right | false = left
{
int start; //the start x coordinate, on the line then increases until reaching the end of the image
int end = dim.width;
graph.setColor(Color.red);
graph.fillRect(pointX.x - 8, pointX.y -8, 16, 16);
graph.setColor(Color.yellow);
graph.fillRect(pointY.x - 8, pointY.y -8, 16, 16);
for (int times = 0; times < dim.height; ++times) //horizontal drawer
{
System.out.println(times);
start = (int)((times-diff.y)/slope + diff.y); //this is where it goes wrong?
for (int value = start; value < end; ++value)
{
graph.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255), 100));
graph.fillRect(value, times, 1, 1);
}
}
graph.dispose();
}
else
{
int start; //the start x coordinate, on the line then increases until reaching the end of the image
int end = dim.width;
graph.setColor(Color.red);
graph.fillRect(pointX.x - 8, pointX.y -8, 16, 16);
graph.setColor(Color.yellow);
graph.fillRect(pointY.x - 8, pointY.y -8, 16, 16);
for (int times = 0; times < dim.height; ++times) //horizontal drawer
{
System.out.println(times);
start = (int)((times-diff.y)/slope);
for (int value = end; value < start; --value)
{
graph.setColor(new Color(rand.nextInt(255), rand.nextInt(255), rand.nextInt(255), 100));
graph.fillRect(value, times, 1, 1);
}
}
graph.dispose();
}
i can't get it to work like i showed in the picture above, all it does is either nothing, or offset from the 2 points.
Also, sometimes it freezes for no reason, so idk what will happen if i make more iterations of this :/
The pattern generation element of your code should only take about 3 lines, including rotation, colour pattern modulation and all as a function of iterations of i.
I will try and be clear:
you don't need a bar/line to generate your maps, you need any pattern on one/2 axes that starts off half of the period of the map and that gets a smaller and smaller proportion of the map or a smaller and smaller period.
pattern:
A line is round(x); or round (x+y) or round(sin(x+y +translatebar)+barwidth)<--a real bar in middle not just on side //
you can do curvy and zigzag lines later and 2D lines using additions and multiplications of X and Y functions. That function is essentially just a single line where you can change it X value so that rotates.
Rotation:
instead of a functional X every time which make a vertical line, you need to use sinus and co sinus function to generate X and Y values.
4 example 30; rotation is : round( X * 0.866+ Y* 0.5)
Get the sine and cosine of a random values and it will give you random rotations of your pattern the handy thing is that you just make a random value of your loop iteration and send it to a sign cosine.
OK i ll write this in pseudocode it will be simpler:
var pattern = 0; // black canvas
for(var i=1; i=100; i++)
{
pattern += round((sin (X*sin(pseudorand(i)) + Y*cos(pseudorand(i)) + translation) + roundshift )*strength;
}
The above loop will generate thousands of map patterns by adding bars of different rotations.
Round = quantizes your sin(XY) function so it is just black and white / red grey.
Sin(XY) = a variable function to use as a pattern, quantized by round to 0/1 values... multiply and clamp that value in the same line so it doesnt exceed 1 or 0
roundshift = value inside round(sin) pattern that shifts the sin down or up inside the round value resulting in smaller or larger amouts of black/white ration of each iteration. its a multiple of i so it's a function of i, gets smaller every loop.
xsin(rnd i) ycos(rnd i) = rotates your pattern both rnd's are same number necessarily.
translate value = when you +/- a number to a Sin(x+translate). it moves bar backwards/forwards
in the end your pattern value will equals maxiumum 100, so devide by 100 so it's 0-1 or mult by 2.56 for 256, and use a color randomiser to make RGB random multiples of your pattern value.
The above loop obviously needs to run once for every pixel x y.
i dont know how to do the canvas array/texture addin pixels in JS, it should be easy.
The above code will give you great patterns and visual feedback of your errors so you should be able to refine it very nicely, only think i missed is clamp to 0-1 values of sin (-1 1)+ roundshift result.
so a bar is round(sin(xy)+translate), and you can use many many functions of xy added muptiplied sins to add together everything else instead bars, graph circles, squares, wiggles, ovals, rectangles etc.
there is a website all about patterns of this type, except for ordered angles and say 5-6 iterations, using dots bars triangles etc, he is Canadian and on deviant art as well, if there weren't so many TD pattern generated I could find his website!
Here is a website explaining the process of "pattern piling" it's overlaying many shapes in smaller and smaller iterations.
only difference is he uses ordered rotations to create symmetry, and you want random rotations to create chaos maps.
see all the pics of piled patterns in 2d, he has many examples on deviant art and his site, i learnt alot from this guy:
http://algorithmic-worlds.net/info/info.php?page=pilpat
here is more work of superimposed smaller and smaller patterns in symmetry rotations:
https://www.google.com/search?q=Samuel+Monnier&espv=210&es_sm=93&source=lnms&tbm=isch&sa=X&ei=It0AU9uTCOn20gXXv4G4Cw&ved=0CAkQ_AUoAQ&biw=1365&bih=911
same as this using random sin cos rotations.
I am creating objects on a line in a window created by this piece of code:
void createTurtles() {
int nrTurtles = Keyboard.nextInt("Set amount of turtles: ");
w = new GraphicsWindow(500, 300);
drawLinez();
for (int k = 1; k <= nrTurtles; k++) {
Turtle t = new Turtle(w, 50, 50 + k*10);
t.right(90);
t.setSpeed(100);
t.penDown();
turtles.add(t);
}
}
This codeline:
Turtle t = new Turtle(w, 50, 50 + k*10);
Creates one turtle at the time. Right now i have set that the turtles will have the Y coordinat of 50, and the X coordinat of 50+k*10. This is because the line starts at the X coordinat of 50 and stops at the X coordinat of 250.
Now what i want is, based on the nr of turtles created (user inputs this), i want the turtles to be spread on this line evenly. How to do it? It has do to with the line that i wrote and maybe the k value or the 10.
The line is illustrated in the picture (see link below), its the red line, that the number of turtles are created at.
Devide the height - 100 of the window by the number of turtles and you will have your distanceBetweenTurles:
int nrTurtles = Keyboard.nextInt("Set amount of turtles: ");
int height = 300;
w = new GraphicsWindow(500, height);
drawLinez();
double distanceBetweenTurles = (height - 100.0) / nrTurtles;
for (int k = 1; k <= nrTurtles; k++) {
Turtle t = new Turtle(w, 50, 50 + (int) (k * distanceBetweenTurtles));
t.right(90);
t.setSpeed(100);
t.penDown();
turtles.add(t);
}