How setup a Max Width and Height resizing for those shape? - javafx

I've seen this code that builds, my attention is to fix the resizing of those shape, and when I move them how can I block the shape to not move out of the window ?
I tried to fix resizing to not exceed when x is between 100 and 300, it works but when I try to decrease the shape size it does not move any more
static void enableDrag(Circle node, boolean canDragX, boolean canDragY, DragHandler dragHandler) {
final Delta dragDelta = new Delta();
node.setOnMousePressed(mouseEvent -> {
// record a delta distance for the drag and drop operation.
dragDelta.x = node.getCenterX() - mouseEvent.getX();
dragDelta.y = node.getCenterY() - mouseEvent.getY();
node.getScene().setCursor(Cursor.MOVE);
});
node.setOnMouseReleased(mouseEvent -> {
node.getScene().setCursor(Cursor.HAND);
});
node.setOnMouseDragged(mouseEvent -> {
double oldX = node.getCenterX();
double oldY = node.getCenterY();
System.out.println(node.getCenterX());
if(node.getCenterX()<=300 && node.getCenterX()>100){
System.out.println();
double newX = mouseEvent.getX() + dragDelta.x;
if (canDragX && newX > 0 && newX < node.getScene().getWidth()) {
node.setCenterX(newX);
}
double newY = mouseEvent.getY() + dragDelta.y;
if (canDragY && newY > 0 && newY < node.getScene().getHeight()) {
node.setCenterY(newY);
}
newX = node.getCenterX();
newY = node.getCenterY();
if (dragHandler != null && (newX != oldX || newY != oldY)) {
dragHandler.handle(oldX, oldY, newX, newY);
}
}
});
node.setOnMouseEntered(mouseEvent -> {
if (!mouseEvent.isPrimaryButtonDown()) {
node.getScene().setCursor(Cursor.HAND);
}
});
node.setOnMouseExited(mouseEvent -> {
if (!mouseEvent.isPrimaryButtonDown()) {
node.getScene().setCursor(Cursor.DEFAULT);
}
});
}

Related

Trouble when rendering voxels with pathtracing

I'm currently working on a pathtracer in c and open cl.
I'm using this algorithm for rendering. The first collision works well, however, from the second collision onwards there is a dark shadow on the lower side of the voxels.
This is the color of the voxel the initial ray hits:
result
This is the color of the voxel that the second ray hits:
result
And this is the result after rendering to a depth of 1000:
result
This is the code I used (openCL):
int cast_ray(Renderer *r, Ray ray, float3 *hitPos, int3 *normal, Material *material) {
int3 voxel = convert_int3(ray.origin);
int3 step = {
(ray.direction.x >= 0) ? 1 : -1,
(ray.direction.y >= 0) ? 1 : -1,
(ray.direction.z >= 0) ? 1 : -1
};
float3 tMax = {
(ray.direction.x != 0) ? (voxel.x + step.x - ray.origin.x) / ray.direction.x : MAXFLOAT,
(ray.direction.y != 0) ? (voxel.y + step.y - ray.origin.y) / ray.direction.y : MAXFLOAT,
(ray.direction.z != 0) ? (voxel.z + step.z - ray.origin.z) / ray.direction.z : MAXFLOAT
};
float3 tDelta = {
(ray.direction.x != 0) ? 1 / ray.direction.x * step.x : MAXFLOAT,
(ray.direction.y != 0) ? 1 / ray.direction.y * step.y : MAXFLOAT,
(ray.direction.z != 0) ? 1 / ray.direction.z * step.z : MAXFLOAT
};
int side;
while(1) {
if(tMax.x < tMax.y) {
if(tMax.x < tMax.z) {
voxel.x += step.x;
tMax.x += tDelta.x;
side = 0;
} else {
voxel.z += step.z;
tMax.z += tDelta.z;
side = 2;
}
} else {
if(tMax.y < tMax.z) {
voxel.y += step.y;
tMax.y += tDelta.y;
side = 1;
} else {
voxel.z += step.z;
tMax.z += tDelta.z;
side = 2;
}
}
if(out_of_scene(r, voxel))
return 0;
MaterialID id = get_material_ID(r, voxel);
if(id == 0)
continue;
*material = get_material(r, id);
switch(side) {
case 0:
hitPos->x = (float)voxel.x;
hitPos->y = ray.origin.y + (hitPos->x - ray.origin.x) * ray.direction.y / ray.direction.x;
hitPos->z = ray.origin.z + (hitPos->x - ray.origin.x) * ray.direction.z / ray.direction.x;
*normal = (int3){-step.x, 0, 0};
break;
case 1:
hitPos->y = (float)voxel.y;
hitPos->x = ray.origin.x + (hitPos->y - ray.origin.y) * ray.direction.x / ray.direction.y;
hitPos->z = ray.origin.z + (hitPos->y - ray.origin.y) * ray.direction.z / ray.direction.y;
*normal = (int3){0, -step.y, 0};
break;
case 2:
hitPos->z = (float)voxel.z;
hitPos->y = ray.origin.y + (hitPos->z - ray.origin.z) * ray.direction.y / ray.direction.z;
hitPos->x = ray.origin.x + (hitPos->z - ray.origin.z) * ray.direction.x / ray.direction.z;
*normal = (int3){0, 0, -step.z};
break;
}
return 1;
}
}
float3 get_color(Renderer *r, Ray ray) {
float3 mask = 1;
float3 color = 0;
int maxDepth = 1000;
for(int i = 0; i < maxDepth; i++) {
float3 hitPos;
int3 iNormal;
Material material;
if(cast_ray(r, ray, &hitPos, &iNormal, &material)) {
float3 fNormal = convert_float3(iNormal);
if(material.type == 1) {
color = mask * material.color;
break;
} else if(material.type == 2) {
float3 direction = fNormal + random_unit_vector(r->rng);
ray = (Ray){hitPos, direction};
mask *= material.color;
} else if(material.type == 3) {
float3 direction = reflection_dir(ray.direction, fNormal) + random_unit_vector(r->rng) * material.fuzzyness;
ray = (Ray){hitPos, direction};
mask = mask * (1 - material.tint) + mask * material.color * material.tint;
}
} else {
color = mask * r->bgColor;
break;
}
// if(i == 1)
// return material.color;
}
return color;
}
I think that the problem is that the new origin of the ray is somehow not correct, but I can't find a way to fix it.

Automatically Crop Image in JavaFX

I have a program which visualizes several Images through an ImageView , which are Fit to a size of 55x55 pixels up from around 32x32 pixels.
Unfortunately, all images have a "border" of transparent background, so the images are displayed with a gap inbetween.
Is there a way to crop an Image in javaFX so that it gets reduced to the actual picture?
Example:
desired look (Badly cropped out by hand)
actual look
Afaik there is no build in method for this. As #Slaw mentioned in his comment, you need to use the PixelReader to check for empty rows/columns. Based on that info you can set the viewport property for the ImageView:
#Override
public void start(Stage primaryStage) {
// using stackoverflow logo, since your image is completely opaque
Image image = new Image("https://cdn.sstatic.net/Sites/stackoverflow/company/img/logos/so/so-icon.png");
ImageView imageView = new ImageView(image);
int w = (int) image.getWidth();
int h = (int) image.getHeight();
int firstNonEmptyColumn = 0;
int firstNonEmptyRow = 0;
int lastNonEmptyColumn = w - 1;
int lastNonEmptyRow = h - 1;
PixelReader reader = image.getPixelReader();
outer: for (; firstNonEmptyColumn < w; firstNonEmptyColumn++) {
for (int y = 0; y < h; y++) {
// stop, if most significant byte (alpha channel) is != 0
if ((reader.getArgb(firstNonEmptyColumn, y) & 0xFF000000) != 0) {
break outer;
}
}
}
if (firstNonEmptyColumn == w) {
imageView.setImage(null); // image completely transparent
} else {
outer: for (; lastNonEmptyColumn > firstNonEmptyColumn; lastNonEmptyColumn--) {
for (int y = 0; y < h; y++) {
if ((reader.getArgb(lastNonEmptyColumn, y) & 0xFF000000) != 0) {
break outer;
}
}
}
outer: for (; firstNonEmptyRow < h; firstNonEmptyRow++) {
// use info for columns to reduce the amount of pixels that need checking
for (int x = firstNonEmptyColumn; x <= lastNonEmptyColumn; x++) {
if ((reader.getArgb(x, firstNonEmptyRow) & 0xFF000000) != 0) {
break outer;
}
}
}
outer: for (; lastNonEmptyRow > firstNonEmptyRow; lastNonEmptyRow--) {
for (int x = firstNonEmptyColumn; x <= lastNonEmptyColumn; x++) {
if ((reader.getArgb(x, lastNonEmptyRow) & 0xFF000000) != 0) {
break outer;
}
}
}
// set viewport to only show the opaque parts
imageView.setViewport(new Rectangle2D(
firstNonEmptyColumn,
firstNonEmptyRow,
lastNonEmptyColumn - firstNonEmptyColumn + 1,
lastNonEmptyRow - firstNonEmptyRow + 1));
}
// visualize image bounds
Rectangle rect = new Rectangle(imageView.prefWidth(-1), imageView.prefHeight(-1), Color.LIGHTGREEN);
StackPane root = new StackPane(rect, imageView);
root.setStyle("-fx-background-color:blue");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}

Recursive Method StackOverflow Error - Minesweeper

I am writing the recursive method for a minesweeper game and I am encountering a stackOverflow error in the recursive method that clears out empty spaces, The error does not occur when checking for 3 of the surrounding spaces but only when checking all eight. Can you please help identify the issue?
The stack trace is :
Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError
at java.awt.Component.firePropertyChange(Component.java:8419)
at javax.swing.AbstractButton.setText(AbstractButton.java:306)
at Minesweeper.Minesweeper.showTile(Minesweeper.java:105)
at Minesweeper.Minesweeper.clearEmpty(Minesweeper.java:137)
at Minesweeper.Minesweeper.clearEmpty(Minesweeper.java:177)
The class:
public class Minesweeper implements ActionListener {
JFrame frame = new JFrame("Minesweeper");
JButton reset = new JButton("Reset");
JButton solve = new JButton("Solve");
JToggleButton[][] buttons = new JToggleButton[20][20];
int[][] counts = new int [20][20];
Container grid = new Container();
final int MINE = 10;
public static void main(String[] args)
{
new Minesweeper();
}
public Minesweeper()
{
frame.setSize(600, 600);
frame.setLayout(new BorderLayout());
frame.add(reset, BorderLayout.NORTH);
frame.add(solve, BorderLayout.SOUTH);
reset.addActionListener(this);
solve.addActionListener(this);
grid.setLayout(new GridLayout(20, 20));
for (int r = 0; r < buttons.length; r++) {
for (int c = 0; c < buttons[0].length; c++) {
buttons[r][c] = new JToggleButton();
buttons[r][c].addActionListener(this);
grid.add(buttons[r][c]);
buttons[r][c].setSize(frame.getWidth() / 20, frame.getHeight() / 22);
}
}
frame.add(grid,BorderLayout.CENTER);
addRandomMines();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public void addRandomMines()
{
ArrayList<Integer> mineList = new ArrayList<Integer>();
for (int x = 0; x < counts.length; x++) {
for (int y = 0; y < counts[0].length; y++){
mineList.add((x*100)+y);
}
}
counts = new int[20][20];
for (int i = 0; i < 30; i++) {
int choice = (int)(Math.random()*mineList.size());
counts[mineList.get(choice)/100][mineList.get(choice)%100] = MINE;
mineList.remove(choice);
}
for (int x = 0; x < counts.length; x++) {
for (int y = 0; y < counts[0].length; y++){
if (counts[x][y]!=MINE) {
int mineCount = 0;
if (x > 0 && y > 0 && counts[x - 1][y - 1] == MINE)
mineCount++;
if (y > 0 && counts[x][y - 1] == MINE)
mineCount++;
if (x > 0 && counts[x - 1][y] == MINE)
mineCount++;
if (x < counts.length - 1 && counts[x + 1][y] == MINE)
mineCount++;
if (y < counts.length - 1 && counts[x][y + 1] == MINE)
mineCount++;
if (x < counts.length - 1 && y < counts.length - 1 && counts[x + 1][y + 1] == MINE)
mineCount++;
if (x > 0 && y < counts.length - 1 && counts[x - 1][y + 1] == MINE)
mineCount++;
if (x < counts.length - 1 && y > 0 && counts[x + 1][y - 1] == MINE)
mineCount++;
counts[x][y] = mineCount;
}
}
}
}
public void showTile(int r, int c)
{
if (counts[r][c] == 0) {
buttons[r][c].setText("");
buttons[r][c].setSelected(true);
}
else if (counts[r][c]==MINE) {
buttons[r][c].setForeground(Color.red);
buttons[r][c].setText("X");
buttons[r][c].setSelected(true);
}
else {
buttons[r][c].setText(counts[r][c] + "");
if (counts[r][c]==1)
buttons[r][c].setForeground(Color.blue);
else if (counts[r][c]==2)
buttons[r][c].setForeground(Color.magenta);
else if (counts[r][c]==3)
buttons[r][c].setForeground(Color.green);
buttons[r][c].setSelected(true);
}
}
public void lostGame() {
for (int x = 0; x < buttons.length; x++) {
for (int y = 0; y < buttons[0].length; y++) {
if (counts[x][y]==MINE) {
showTile(x, y);
}
}
}
}
public void clearEmpty(ArrayList<Integer> toClear)
{
if (toClear.size()==0){
return;
}
else {
int x = toClear.get(0)/100;
int y = toClear.get(0)%100;
toClear.remove(0);
if (counts[x][y]==0) {
if (x > 0 && y > 0) {
showTile(x-1,y-1);
if (counts[x-1][y-1]==0)
toClear.add((x-1)*100 + (y-1));
}
if (y > 0) {
showTile(x,y-1);
if (counts[x][y-1]==0)
toClear.add(x*100 + (y-1));
}
if (x <counts.length-1 && y > 0) {
showTile(x+1,y-1);
if (counts[x+1][y-1]==0)
toClear.add((x+1)*100 + (y-1));
}
if (x > 0) {
showTile(x-1,y);
if (counts[x-1][y]==0)
toClear.add((x-1)*100 + y);
}
if (x <counts.length-1 && y > 0) {
showTile(x+1,y);
if (counts[x+1][y]==0)
toClear.add((x+1)*100 + y);
}
if (x > 0 && y < counts[0].length-1) {
showTile(x-1,y+1);
if (counts[x-1][y+1]==0)
toClear.add((x-1)*100 + (y+1));
}
if (y < counts[0].length-1) {
showTile(x,y+1);
if (counts[x][y+1]==0)
toClear.add(x*100 + (y+1));
}
if (x <counts.length-1 && y < counts[0].length-1) {
showTile(x+1,y+1);
if (counts[x+1][y+1]==0)
toClear.add((x+1)*100 + (y+1));
}
}
clearEmpty(toClear);
}
}
#Override
public void actionPerformed(ActionEvent event) {
if (event.getSource().equals(reset)) {
for (int r = 0; r < buttons.length; r++) {
for (int c = 0; c < buttons[0].length; c++) {
buttons[r][c].setSelected(false);
buttons[r][c].setText("");
}
}
addRandomMines();
} else if (event.getSource().equals(solve)) {
} else {
for (int r = 0; r < buttons.length; r++) {
for (int c = 0; c < buttons[0].length; c++) {
if (event.getSource().equals(buttons[r][c])) {
if (counts[r][c] == MINE) {
showTile(r, c);
lostGame();
}
else if (counts[r][c] == 0) {
ArrayList<Integer> toClear = new ArrayList<Integer>();
toClear.add(r*100+c);
clearEmpty(toClear);
}
else {
showTile(r, c);
}
}
}
}
}
}
}
I think that you're using the wrong algorithm...
Try to use an iterative instead of an recursive approach.
As User404 already mentioned your current algorithm keeps the list growing...
For your implementation: you have 400 tiles. Assuming (worst case) all tiles are empty you call your method clearEmpty() once. You will find out that all 8 neighbors are empty so you add this 8 neighbors to the list while only removing the first one. Now you pass the array to the method again (2nd call) and will find 8 neighbors for the first entry again. So your 3rd call will have a list with 15 tiles.
Real problem
This way you will never come to an end as you never check if the current checked tile is already cleared but you only add to the list more than you will ever remove.
Solution
At least you should check if the tile you want to add to the list is already cleared or is already in the list.
You example is a clear example why recursive algorithms should be used with care as the termination is difficult sometimes and also you have to take care that no work is done multiple times.

qt q3table eat sectionHandleDoubleClicked

i am using q3Table.
i want to expand the column width to max item width by double click the edge of the header
while trying to connect to h3Header::sectionHandleDoubleClicked
i found in Q3Table code that it override the header double click event and not emitting the signal.
class Q_COMPAT_EXPORT Q3TableHeader : public Q3Header
{
void mouseDoubleClickEvent(QMouseEvent *e);
...
void Q3TableHeader::mouseDoubleClickEvent(QMouseEvent *e)
{
if (e->button() != LeftButton)
return;
if (isResizing) {
int p = real_pos(e->pos(), orientation()) + offset();
int section = sectionAt(p);
if (section == -1)
return;
section--;
if (p >= sectionPos(count() - 1) + sectionSize(count() - 1))
++section;
while (sectionSize(section) == 0)
section--;
if (section < 0)
return;
int oldSize = sectionSize(section);
if (orientation() == Horizontal) {
table->adjustColumn(section);
int newSize = sectionSize(section);
if (oldSize != newSize)
emit sizeChange(section, oldSize, newSize);
for (int i = 0; i < table->numCols(); ++i) {
if (table->isColumnSelected(i) && sectionSize(i) != 0)
table->adjustColumn(i);
}
} else {
table->adjustRow(section);
int newSize = sectionSize(section);
if (oldSize != newSize)
emit sizeChange(section, oldSize, newSize);
for (int i = 0; i < table->numRows(); ++i) {
if (table->isRowSelected(i) && sectionSize(i) != 0)
table->adjustRow(i);
}
}
}
}
as in the original q3Header a signal is emitted.
void Q3Header::mouseDoubleClickEvent(QMouseEvent *e)
{
int p = orient == Qt::Horizontal ? e->pos().x() : e->pos().y();
p += offset();
if(reverse())
p = d->lastPos - p;
int header = handleAt(p);
if (header >= 0)
emit sectionHandleDoubleClicked(header);
}
how can i get the same effect as sectionHandleDoubleClicked?
or how can i achieve this effect?

Qt keeping mouse centered

I'm wondering if anyone has a trick to keep the mouse position centered in a (QGL)widget for Qt. I read that one could set the mouseposition after finding the delta, but this way works very buggy for me. Mouse events are not properly registered, any if they do, very jumpy.
void World::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
GLfloat dx = GLfloat(event->x() - lastPos.x()) / width();
GLfloat dy = GLfloat(event->y() - lastPos.y()) / height();
player->rotHorizontal += 360.0 * dx;
if(player->rotHorizontal < 0.0)
player->rotHorizontal += 360.0;
else if(player->rotHorizontal > +360.0)
player->rotHorizontal -= 360.0;
player->rotVertical += 360.0 * dy;
if (player->rotVertical > MAX_ROTATION_UP) {
player->rotVertical = MAX_ROTATION_UP;
} else if (player->rotVertical < -MAX_ROTATION_UP) {
player->rotVertical = -MAX_ROTATION_UP;
}
}
// int diffX = event->pos().x() - lastPos.x() % 20;
// int diffY = event->pos().y() - lastPos.y() % 20;
// if (diffY > 10 || diffX > 10 || diffY < -10 || diffX < -10) {
// QPoint glob = mapToGlobal(QPoint(this->pos().x() + width()/2, this->pos().y() + height()/2));
// QCursor::setPos(glob);
// }
lastPos = event->pos();
QGLWidget::mouseMoveEvent(event);
}
I commented out the code which would keep the mouse centered. If this would work, I would place it in the leftclick area.
Fixed:
void World::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton) {
GLfloat dx = GLfloat(event->x() - lastPos.x()) / width();
GLfloat dy = GLfloat(event->y() - lastPos.y()) / height();
player->rotHorizontal += 360.0 * dx;
if(player->rotHorizontal < 0.0)
player->rotHorizontal += 360.0;
else if(player->rotHorizontal > +360.0)
player->rotHorizontal -= 360.0;
player->rotVertical += 360.0 * dy;
if (player->rotVertical > MAX_ROTATION_UP) {
player->rotVertical = MAX_ROTATION_UP;
} else if (player->rotVertical < -MAX_ROTATION_UP) {
player->rotVertical = -MAX_ROTATION_UP;
}
}
QPoint glob = mapToGlobal(QPoint(width()/2,height()/2));
QCursor::setPos(glob);
lastPos = QPoint(width()/2,height()/2);
QGLWidget::mouseMoveEvent(event);
}

Resources