Can you create numbers around the analog clock? - processing

so, as an assaignment i want to make an analog clock, and i am pretty far. I only need the numbers around the clock, but i cant figure out how to make these. I have made some dots right now, but i want to replace theese with the numbers 1-12.. does any1 know an easy and fast way of doing this? my code is as following:
let cx, cy;
let secondsRadius;
let minutesRadius;
let hoursRadius;
let clockDiameter;
function setup() {
createCanvas(800, 800);
let radius= min(width,height)/2;
secondsRadius=radius*0.71;
minutesRadius = radius*0.6;
hoursRadius = radius*0.5;
clockDiameter = radius*1.7;
cx = width/2;
cy = height/2;
}
function draw() {
background("pink");
noStroke();
fill(244, 122, 158);
ellipse(cx, cy, clockDiameter + 25, clockDiameter + 25);
fill("green");
ellipse(cx,cy,clockDiameter, clockDiameter);
let s = map(second(), 0, 60, 0, TWO_PI) - HALF_PI;
let m = map(minute() + norm(second(), 0, 60), 0, 60, 0, TWO_PI) - HALF_PI;
let h = map(hour() + norm(minute(), 0, 60), 0, 24, 0, TWO_PI *2) - HALF_PI;
stroke(255);
strokeWeight(1);
line(cx, cy, cx + cos(s) * secondsRadius, cy + sin(s) * secondsRadius);
strokeWeight(2);
line(cx, cy, cx + cos(m) * minutesRadius, cy + sin(m) * minutesRadius);
strokeWeight(4);
line(cx, cy, cx + cos(h) * hoursRadius, cy + sin(h) * hoursRadius);
strokeWeight(2);
beginShape(POINTS);
for (let a = 0; a < 360; a += 6) {
let angle = radians(a);
let x = cx + cos(angle) * secondsRadius;
let y = cy + sin(angle) * secondsRadius;
vertex(x, y);
}
endShape();
}```

As a quick and dirty:) answer - just add something like that before the last brace:
textSize(36);
fill("white");
noStroke()
for (i = 0; i < 12; i++) {
v = p5.Vector.fromAngle((i + 1) / 12.0 * TAU - HALF_PI);
v.mult(310);
text(i + 1, 382 + v.x, 416 + v.y);
}
My live working demo (your code + this addition) is on ReplIt

Related

processing collision test return false at the beginning

I am doing the collision test for the programme, and I tried to insert the test into draw() and I'm expecting it to display "GameOver" and no further events will result any change.
float x;
float y;
float w;
float h;
float xPed;
float yPed;
float yPedc;
float objectX;
float objectY;
float objectWidth;
float objectHeight;
float triangleWidth;
float triangleHeight;
float dia;
int speed = 2;
boolean gameOver;
int N_LANES = 1;
void setup() {
size(1200, 400);
background(255);
x = width / 60;
y = height / 40;
w = width / 80;
xPed = width / 2;
triangleWidth = height / 4;
triangleHeight = 2.5 * w;
yPed = height - 3 * w;
yPedc = 2.5 * w / 2;
dia = w / 2;
h = w / 2;
objectX = x + 2 * w;
objectY = y + 5 * h;
objectWidth = 4 * w;
objectHeight = 10 * h;
gameOver = false;
}
void draw() {
//reset background
background(255);
line(0, height/4, width, height/4);
vehicle();
pedestrian();
// collision detect
if (gameOver == true) {
textSize(100);
fill(255, 0, 0);
text("Game Over", width / 3, height / 2);
}
}
void vehicle() {
//moving vehicle
x += speed;
// reset vehicle
noFill();
if (x > width) {
x = 0;
} else if (x < 0) {
x = width;
}
for (int i = 0; i < N_LANES; i++) {
//head of vehicle
fill(0, 194, 0, 50);
rect(x, y, w, h);
rect(x + 3 * w, y, w, h);
rect(x, y + h, 4 * w, 4 *h);
//eyes of vehicle
fill(0);
rect(x + w, 3 * y, w * 0.85, h);
rect(x + 3 * w, 3 * y, w * 0.85, h);
//body of vehicle
fill(0, 240, 0, 80);
rect(x + 1.5 * w, 6.3 * h, 1.5 * w, 3 *h );
//left arm
line(x + 1.5 *w, 6.3 * h, x + 0.5 * w, 7.3 * h);
//right arm
line(x + 3 * w, 6.3 * h, x + 4 * w, 7.3 * h);
//left leg
line(x + 1.5 * w, 9.3 * h, x + w, 11.3 * h);
//right leg
line(x + 3 * w, 9.3 * h, x + 3.5 * w, 11.3 * h);
}
}
// draw pedestrian
void pedestrian() {
fill(255, 140, 0, 70);
//body of pedestrian
triangle(xPed, yPed, xPed - triangleWidth / 2, yPed + 2.5 * w, xPed + triangleWidth / 2, yPed + 2.5 * w);
fill(0);
circle(xPed + triangleWidth / 4, yPed, dia);
circle(xPed - triangleWidth / 4, yPed, dia);
fill(255, 165, 0);
ellipse(xPed, yPed + w, 1.5 * dia, 3 * dia);
}
// arrow key moving
void keyPressed() {
if (gameOver != true) {
if (key == CODED) {
if (keyCode == UP) {
yPed -= height / 4;
if (yPed <= 0) {
yPed = height - 3 * w;
}
}
if (keyCode == DOWN) {
yPed += height / 4;
if (yPed > height) {
yPed = height - 3 * w;
}
}
if (keyCode==LEFT) {
xPed -= height / 4;
if (xPed < 0 + triangleWidth / 2) {
xPed = width / 2;
}
}
if (keyCode==RIGHT) {
xPed += height / 4;
if (xPed > width - triangleWidth / 2) {
xPed = width / 2;
}
}
}
}
}
boolean gameOver() {
// optional visualise collision objects
rect(objectX, objectY, objectWidth, objectHeight);
rect(xPed, yPed, triangleWidth, triangleHeight);
// x axis
float distX = abs( (objectX + objectWidth / 2) - (xPed + triangleWidth / 2) );
// y axis
float distY = abs( (objectY + objectHeight / 2) - (yPedc + triangleHeight / 2) );
// half combined x distance
float combinedHalfWidth = ( (objectWidth / 2) + (triangleWidth / 2) );
// half combined y distance
float combinedHalfHeight = ( (objectHeight / 2) + (triangleHeight / 2) );
// check collision
if (distX < combinedHalfWidth) {
if (distY < combinedHalfHeight) {
return true;
}
}
return false;
}
I tried to insert the gameOver boolean into draw and it returns the same value everytime.
Just wondering what the logical problem or the coding problem is.
As Rabbid76 mentions, you should format the code correctly first.
Let's assume the code been copied from a pdf with code snippets and that's how formatting got messed up.
The code still has a few glaring bugs:
confusingly you're using both a boolean variable gameOver and a boolean function gameOver() and the variable isn't always updated. (In fact gameOver is only set once in setup() and gameOver() which actually does the collision detection is never called). I recommend either update the boolean variable, or simpler yet, just call gameOver() to compute the collision as needed. This is one of the reasons your code won't behave as you expect.
You're checking collisions between two objects: the vehicle and the pedestrian. However, there are 3 sets of coordinates: x, y, xPed, objectX, objectY. When rendering in draw, the vehicle uses x,y, however, when checking for collisions, gameOver() uses objectX, objectY (which don't match and aren't updated). This is the other reason you're collisions don't behave as expected.
aside from the question you've asked, N_LANES is used in a for loop, but never declared. Even if I declare it, the for loop uses the exact same x,y coordinates, making the for loop redundant.
Here's a formatted version of your code with extra bounding boxes highlighting what the collision function is checking against (and commenting a few unused variables):
float x;
float y;
float w;
float h;
float xPed;
float yPed;
//float yPedc;
float objectX;
float objectY;
float objectWidth;
float objectHeight;
float triangleWidth;
float triangleHeight;
float dia;
int speed = 2;
//boolean gameOver;
int N_LANES = 1;
void setup() {
size(1200, 400);
background(255);
x = width / 60;
y = height / 40;
w = width / 80;
xPed = width / 2;
triangleWidth = height / 4;
triangleHeight = 2.5 * w;
yPed = height - 3 * w;
//yPedc = 2.5 * w / 2;
dia = w / 2;
h = w / 2;
objectX = x + 2 * w;
objectY = y + 5 * h;
objectWidth = 4 * w;
objectHeight = 10 * h;
//gameOver = false;
}
void draw() {
//reset background
background(255);
line(0, height/4, width, height/4);
vehicle();
pedestrian();
// collision detect
if (gameOver() == true) {
textSize(100);
fill(255, 0, 0);
text("Game Over", width / 3, height / 2);
}
}
void vehicle() {
//moving vehicle
x += speed;
// reset vehicle
noFill();
if (x > width) {
x = 0;
} else if (x < 0) {
x = width;
}
for (int i = 0; i < N_LANES; i++) {
//head of vehicle
fill(0, 194, 0, 50);
rect(x, y, w, h);
rect(x + 3 * w, y, w, h);
rect(x, y + h, 4 * w, 4 *h);
//eyes of vehicle
fill(0);
rect(x + w, 3 * y, w * 0.85, h);
rect(x + 3 * w, 3 * y, w * 0.85, h);
//body of vehicle
fill(0, 240, 0, 80);
rect(x + 1.5 * w, 6.3 * h, 1.5 * w, 3 *h );
//left arm
line(x + 1.5 *w, 6.3 * h, x + 0.5 * w, 7.3 * h);
//right arm
line(x + 3 * w, 6.3 * h, x + 4 * w, 7.3 * h);
//left leg
line(x + 1.5 * w, 9.3 * h, x + w, 11.3 * h);
//right leg
line(x + 3 * w, 9.3 * h, x + 3.5 * w, 11.3 * h);
}
}
// draw pedestrian
void pedestrian() {
fill(255, 140, 0, 70);
//body of pedestrian
triangle(xPed, yPed, xPed - triangleWidth / 2, yPed + 2.5 * w, xPed + triangleWidth / 2, yPed + 2.5 * w);
fill(0);
circle(xPed + triangleWidth / 4, yPed, dia);
circle(xPed - triangleWidth / 4, yPed, dia);
fill(255, 165, 0);
ellipse(xPed, yPed + w, 1.5 * dia, 3 * dia);
// visualise bounding box
//fill(255, 140, 0, 70);
//rect(xPed - triangleWidth / 2, yPed, triangleWidth, triangleHeight);
}
// arrow key moving
void keyPressed() {
if (gameOver() != true) {
if (key == CODED) {
if (keyCode == UP) {
yPed -= height / 4;
if (yPed <= 0) {
yPed = height - 3 * w;
}
}
if (keyCode == DOWN) {
yPed += height / 4;
if (yPed > height) {
yPed = height - 3 * w;
}
}
if (keyCode==LEFT) {
xPed -= height / 4;
if (xPed < 0 + triangleWidth / 2) {
xPed = width / 2;
}
}
if (keyCode==RIGHT) {
xPed += height / 4;
if (xPed > width - triangleWidth / 2) {
xPed = width / 2;
}
}
}
}
}
boolean gameOver() {
// optional visualise collision objects
rect(objectX, objectY, objectWidth, objectHeight);
rect(xPed, yPed, triangleWidth, triangleHeight);
// x axis
float distX = abs( (objectX + objectWidth / 2) - (xPed + triangleWidth / 2) );
// y axis
float distY = abs( (objectY + objectHeight / 2) - (yPed + triangleHeight / 2) );
// half combined x distance
float combinedHalfWidth = ( (objectWidth / 2) + (triangleWidth / 2) );
// half combined y distance
float combinedHalfHeight = ( (objectHeight / 2) + (triangleHeight / 2) );
// check collision
if (distX < combinedHalfWidth) {
if (distY < combinedHalfHeight) {
return true;
}
}
return false;
}
Here's a version of the code with a few of the 3 notes above applied, somewhat resolving the collision and gameOver state issue:
float x;
float y;
float w;
float h;
float xPed;
float yPed;
float objectWidth;
float objectHeight;
float triangleWidth;
float triangleHeight;
float dia;
int speed = 2;
void setup() {
size(1200, 400);
background(255);
x = width / 60;
y = height / 40;
w = width / 80;
xPed = width / 2;
triangleWidth = height / 4;
triangleHeight = 2.5 * w;
yPed = height - 3 * w;
dia = w / 2;
h = w / 2;
objectWidth = 4 * w;
objectHeight = 10 * h;
}
void draw() {
//reset background
background(255);
line(0, height/4, width, height/4);
vehicle();
pedestrian();
// collision detect
if (gameOver()) {
textSize(100);
fill(255, 0, 0);
text("Game Over", width / 3, height / 2);
}
}
void vehicle() {
//moving vehicle
x += speed;
// reset vehicle
noFill();
if (x > width) {
x = 0;
} else if (x < 0) {
x = width;
}
//head of vehicle
fill(0, 194, 0, 50);
rect(x, y, w, h);
rect(x + 3 * w, y, w, h);
rect(x, y + h, 4 * w, 4 *h);
//eyes of vehicle
fill(0);
rect(x + w, 3 * y, w * 0.85, h);
rect(x + 3 * w, 3 * y, w * 0.85, h);
//body of vehicle
fill(0, 240, 0, 80);
rect(x + 1.5 * w, 6.3 * h, 1.5 * w, 3 *h );
//left arm
line(x + 1.5 *w, 6.3 * h, x + 0.5 * w, 7.3 * h);
//right arm
line(x + 3 * w, 6.3 * h, x + 4 * w, 7.3 * h);
//left leg
line(x + 1.5 * w, 9.3 * h, x + w, 11.3 * h);
//right leg
line(x + 3 * w, 9.3 * h, x + 3.5 * w, 11.3 * h);
}
// draw pedestrian
void pedestrian() {
fill(255, 140, 0, 70);
//body of pedestrian
triangle(xPed, yPed, xPed - triangleWidth / 2, yPed + 2.5 * w, xPed + triangleWidth / 2, yPed + 2.5 * w);
fill(0);
circle(xPed + triangleWidth / 4, yPed, dia);
circle(xPed - triangleWidth / 4, yPed, dia);
fill(255, 165, 0);
ellipse(xPed, yPed + w, 1.5 * dia, 3 * dia);
// visualise bounding box
//fill(255, 140, 0, 70);
//rect(xPed - triangleWidth / 2, yPed, triangleWidth, triangleHeight);
}
// arrow key moving
void keyPressed() {
if (!gameOver()) {
if (key == CODED) {
if (keyCode == UP) {
yPed -= height / 4;
if (yPed <= 0) {
yPed = height - 3 * w;
}
}
if (keyCode == DOWN) {
yPed += height / 4;
if (yPed > height) {
yPed = height - 3 * w;
}
}
if (keyCode==LEFT) {
xPed -= height / 4;
if (xPed < 0 + triangleWidth / 2) {
xPed = width / 2;
}
}
if (keyCode==RIGHT) {
xPed += height / 4;
if (xPed > width - triangleWidth / 2) {
xPed = width / 2;
}
}
}
}
}
boolean gameOver() {
// optional visualise collision objects
rect(x, y, objectWidth, objectHeight);
rect(xPed, yPed, triangleWidth, triangleHeight);
// x axis
float distX = abs( (x + objectWidth / 2) - (xPed + triangleWidth / 2) );
// y axis
float distY = abs( (y + objectHeight / 2) - (yPed + triangleHeight / 2) );
// half combined x distance
float combinedHalfWidth = ( (objectWidth / 2) + (triangleWidth / 2) );
// half combined y distance
float combinedHalfHeight = ( (objectHeight / 2) + (triangleHeight / 2) );
// check collision
if (distX < combinedHalfWidth) {
if (distY < combinedHalfHeight) {
return true;
}
}
return false;
}
Notice that the triangle bounding box needs to be moved to the left by half the triangle width ideally.
I'd also like to point you to java.awt.Rectangle which has an intersects() that could be useful:
import java.awt.Rectangle;
float x;
float y;
float w;
float h;
float xPed;
float yPed;
float objectWidth;
float objectHeight;
float triangleWidth;
float triangleHeight;
float dia;
int speed = 2;
Rectangle vehicleBoundingBox;
Rectangle pedestrianBoundingBox;
void setup() {
size(1200, 400);
background(255);
x = width / 60;
y = height / 40;
w = width / 80;
xPed = width / 2;
triangleWidth = height / 4;
triangleHeight = 2.5 * w;
yPed = height - 3 * w;
dia = w / 2;
h = w / 2;
objectWidth = 4 * w;
objectHeight = 10 * h;
vehicleBoundingBox = new Rectangle((int)x, (int)y, (int)objectWidth, (int)objectHeight);
pedestrianBoundingBox = new Rectangle((int)xPed, (int)yPed, (int)triangleWidth, (int)triangleHeight);
}
void draw() {
//reset background
background(255);
line(0, height/4, width, height/4);
vehicle();
pedestrian();
// collision detect
if (gameOver()) {
textSize(100);
fill(255, 0, 0);
text("Game Over", width / 3, height / 2);
}
}
void vehicle() {
//moving vehicle
x += speed;
// reset vehicle
noFill();
if (x > width) {
x = 0;
} else if (x < 0) {
x = width;
}
//head of vehicle
fill(0, 194, 0, 50);
rect(x, y, w, h);
rect(x + 3 * w, y, w, h);
rect(x, y + h, 4 * w, 4 *h);
//eyes of vehicle
fill(0);
rect(x + w, 3 * y, w * 0.85, h);
rect(x + 3 * w, 3 * y, w * 0.85, h);
//body of vehicle
fill(0, 240, 0, 80);
rect(x + 1.5 * w, 6.3 * h, 1.5 * w, 3 *h );
//left arm
line(x + 1.5 *w, 6.3 * h, x + 0.5 * w, 7.3 * h);
//right arm
line(x + 3 * w, 6.3 * h, x + 4 * w, 7.3 * h);
//left leg
line(x + 1.5 * w, 9.3 * h, x + w, 11.3 * h);
//right leg
line(x + 3 * w, 9.3 * h, x + 3.5 * w, 11.3 * h);
}
// draw pedestrian
void pedestrian() {
fill(255, 140, 0, 70);
//body of pedestrian
triangle(xPed, yPed, xPed - triangleWidth / 2, yPed + 2.5 * w, xPed + triangleWidth / 2, yPed + 2.5 * w);
fill(0);
circle(xPed + triangleWidth / 4, yPed, dia);
circle(xPed - triangleWidth / 4, yPed, dia);
fill(255, 165, 0);
ellipse(xPed, yPed + w, 1.5 * dia, 3 * dia);
}
// arrow key moving
void keyPressed() {
if (!gameOver()) {
if (key == CODED) {
if (keyCode == UP) {
yPed -= height / 4;
if (yPed <= 0) {
yPed = height - 3 * w;
}
}
if (keyCode == DOWN) {
yPed += height / 4;
if (yPed > height) {
yPed = height - 3 * w;
}
}
if (keyCode==LEFT) {
xPed -= height / 4;
if (xPed < 0 + triangleWidth / 2) {
xPed = width / 2;
}
}
if (keyCode==RIGHT) {
xPed += height / 4;
if (xPed > width - triangleWidth / 2) {
xPed = width / 2;
}
}
}
}
}
boolean gameOver(){
// update bounding box positions
vehicleBoundingBox.x = (int)x;
vehicleBoundingBox.y = (int)y;
pedestrianBoundingBox.x = (int)(xPed - triangleWidth / 2);
pedestrianBoundingBox.y = (int)yPed;
//optional: visualise boxes
fill(255, 140, 0, 70);
rect(pedestrianBoundingBox.x, pedestrianBoundingBox.y, pedestrianBoundingBox.width, pedestrianBoundingBox.height);
rect(vehicleBoundingBox.x, vehicleBoundingBox.y, vehicleBoundingBox.width, vehicleBoundingBox.height);
return vehicleBoundingBox.intersects(pedestrianBoundingBox);
}
//boolean gameOver() {
// // optional visualise collision objects
// rect(x, y, objectWidth, objectHeight);
// rect(xPed, yPed, triangleWidth, triangleHeight);
// // x axis
// float distX = abs( (x + objectWidth / 2) - (xPed + triangleWidth / 2) );
// // y axis
// float distY = abs( (y + objectHeight / 2) - (yPed + triangleHeight / 2) );
// // half combined x distance
// float combinedHalfWidth = ( (objectWidth / 2) + (triangleWidth / 2) );
// // half combined y distance
// float combinedHalfHeight = ( (objectHeight / 2) + (triangleHeight / 2) );
// // check collision
// if (distX < combinedHalfWidth) {
// if (distY < combinedHalfHeight) {
// return true;
// }
// }
// return false;
//}
void circle(float x, float y, float dia){
ellipse(x, y, dia, dia);
}
Bare in mind, if this is an assignment/homework, you might not be allowed to use java.awt.Rectangle. Speaking of which, if this is an assignment you should mention that in the question.
Update
Here's an updated version better handling the game over state.
float x;
float y;
float w;
float h;
float xPed;
float yPed;
float objectWidth;
float objectHeight;
float triangleWidth;
float triangleHeight;
float dia;
int speed = 2;
// defaults to false
boolean isGameOver;
void setup() {
size(1200, 400);
background(255);
x = width / 60;
y = height / 40;
w = width / 80;
xPed = width / 2;
triangleWidth = height / 4;
triangleHeight = 2.5 * w;
yPed = height - 3 * w;
dia = w / 2;
h = w / 2;
objectWidth = 4 * w;
objectHeight = 10 * h;
}
void draw() {
//reset background
background(255);
line(0, height/4, width, height/4);
if (isGameOver) {
textSize(100);
fill(255, 0, 0);
text("Game Over", width / 3, height / 2);
}else{
// check colloisions only in game state and update game over state
isGameOver = checkCollisions();
vehicle();
pedestrian();
}
}
void vehicle() {
//moving vehicle
x += speed;
// reset vehicle
noFill();
if (x > width) {
x = 0;
} else if (x < 0) {
x = width;
}
//head of vehicle
fill(0, 194, 0, 50);
rect(x, y, w, h);
rect(x + 3 * w, y, w, h);
rect(x, y + h, 4 * w, 4 *h);
//eyes of vehicle
fill(0);
rect(x + w, 3 * y, w * 0.85, h);
rect(x + 3 * w, 3 * y, w * 0.85, h);
//body of vehicle
fill(0, 240, 0, 80);
rect(x + 1.5 * w, 6.3 * h, 1.5 * w, 3 *h );
//left arm
line(x + 1.5 *w, 6.3 * h, x + 0.5 * w, 7.3 * h);
//right arm
line(x + 3 * w, 6.3 * h, x + 4 * w, 7.3 * h);
//left leg
line(x + 1.5 * w, 9.3 * h, x + w, 11.3 * h);
//right leg
line(x + 3 * w, 9.3 * h, x + 3.5 * w, 11.3 * h);
}
// draw pedestrian
void pedestrian() {
fill(255, 140, 0, 70);
//body of pedestrian
triangle(xPed, yPed, xPed - triangleWidth / 2, yPed + 2.5 * w, xPed + triangleWidth / 2, yPed + 2.5 * w);
fill(0);
circle(xPed + triangleWidth / 4, yPed, dia);
circle(xPed - triangleWidth / 4, yPed, dia);
fill(255, 165, 0);
ellipse(xPed, yPed + w, 1.5 * dia, 3 * dia);
// visualise bounding box
//fill(255, 140, 0, 70);
//rect(xPed - triangleWidth / 2, yPed, triangleWidth, triangleHeight);
}
// arrow key moving
void keyPressed() {
if (isGameOver){
// exit game over
isGameOver = false;
// lazy way to restart the game
// normally you'd write & call a reset() function to reset player/vehicle positions, avodiing instant gameOver
setup();
} else {
if (key == CODED) {
if (keyCode == UP) {
yPed -= height / 4;
if (yPed <= 0) {
yPed = height - 3 * w;
}
}
if (keyCode == DOWN) {
yPed += height / 4;
if (yPed > height) {
yPed = height - 3 * w;
}
}
if (keyCode==LEFT) {
xPed -= height / 4;
if (xPed < 0 + triangleWidth / 2) {
xPed = width / 2;
}
}
if (keyCode==RIGHT) {
xPed += height / 4;
if (xPed > width - triangleWidth / 2) {
xPed = width / 2;
}
}
}
}
}
boolean checkCollisions() {
// optional visualise collision objects
fill(255, 140, 0, 70);
rect(x, y, objectWidth, objectHeight);
rect(xPed - triangleWidth / 2, yPed, triangleWidth, triangleHeight);
// x axis
float distX = abs( (x + objectWidth / 2) - xPed );
// y axis
float distY = abs( (y + objectHeight / 2) - (yPed + triangleHeight / 2) );
// half combined x distance
float combinedHalfWidth = ( (objectWidth / 2) + (triangleWidth / 2) );
// half combined y distance
float combinedHalfHeight = ( (objectHeight / 2) + (triangleHeight / 2) );
// check collision
if (distX < combinedHalfWidth) {
if (distY < combinedHalfHeight) {
return true;
}
}
return false;
}
The main changes are:
reintroduced gameOver boolean as isGameOver which is used to change between the two states
renamed gameOver() to checkCollisions() to avoid confusion.
In this case, with just two states, a boolean will do.
It's important to also reset game variables when changing state (e.g. reset player/vehicle positions, etc.)
In case your game may require more states you can use an integer and constants. This answer has a demo code snippet.
If multiple states are required OOP was introduced, this answer also has demo code.

What's wrong in my converting .PDE to .JS?

Hello coding community I need your help.
I took a sketch from openprocessing and I need to convert it into p5.js. The first script is the source code, then below will by my translation. I'm not sure about the syntax.
float x, y, x2, y2, rad, rad2, dist, dist2;
float deg, incr, yIn, rotateBy, ang;
void setup() {
size(600, 600);
background(#02021A);
incr = 1; // numVerts = 360/incr
rad = -20;
rad2 = -160;
dist = 500;
dist2 = 550;
}
void draw() {
noStroke();
fill(#02021A, 10);
rect(0, 0, width, height);
fill(random(0, 255), 255, 255);
rotateBy += .003;
pushMatrix();
translate(width/2, height/2);
rotate(rotateBy);
deg = 0;
while (deg <= 360) {
deg += incr;
ang = radians(deg);
x = cos(ang) * (rad + (dist * noise(y/100, yIn)));
y = sin(ang) * (rad + (dist * noise(x/80, yIn)));
ellipse(x, y, 1.5, 1.5);
x2 = sin(ang) * (rad2 + (dist2 * noise(y2/20, yIn)));
y2 = cos(ang) * (rad2 + (dist2 * noise(y2/20, yIn)));
ellipse(x2, y2, 1, 1);
}
yIn += .005;
popMatrix();
}
This what I've done.
p5.js:
let x, y, x2, y2, rad, rad2, dist, dist2;
let deg, incr, yIn, rotateBy, ang;
function setup() {
createCanvas(600, 600);
background('#02021A');
incr = 1; // numVerts = 360/incr
rad = -20;
rad2 = -160;
dist = 500;
dist2 = 550;
}
function draw() {
noStroke();
fill('#02021A');
rect(0, 0, width, height);
fill(random(0, 255), 255, 255);
rotateBy += '.003';
push();
translate(width/2, height/2);
rotate(rotateBy);
deg = 0;
while (deg <= 360) {
deg += incr;
ang = radians(deg);
x = cos(ang) * (rad + (dist * noise(y/100, yIn)));
y = sin(ang) * (rad + (dist * noise(x/80, yIn)));
ellipse(x, y, 1.5, 1.5);
x2 = sin(ang) * (rad2 + (dist2 * noise(y2/20, yIn)));
y2 = cos(ang) * (rad2 + (dist2 * noise(y2/20, yIn)));
ellipse(x2, y2, 1, 1);
}
yIn += '.005';
pop();
}
But it still doesn't work. Could you help me understand if the syntax is the same in these two languages.
You're almost there, but there are a couple of gotchas:
you declare variables at the top (e.g. float x, y, x2, y2, rad, rad2, dist, dist2;, etc.), however you don't initialize them with values. Because JavaScript is untyped (unlike Java), the interpreter can't guess what type you meant and the variables will be initialised to undefined (while in Java, because they're float type they'll default to 0). Doing math operations on undefined results in NaN (not a number).
you're accidentally incrementing some values by strings instead of floats: rotateBy += '.003'; yIn += '.005';
optional: fill(#02021A, 10); won't work in p5.js, however you can use fill(r,g,b,a) and pass your values in hex notation: fill(0x02, 0x02, 0x1A, 10);
This is your code with these two fixes applied:
let x = 0, y = 0, x2 = 0, y2 = 0, rad = 0, rad2 = 0, dist = 0, dist2 = 0;
let deg = 0, incr = 0, yIn = 0, rotateBy = 0, ang = 0;
function setup() {
createCanvas(600, 600);
background('#02021A');
incr = 1; // numVerts = 360/incr
rad = -20;
rad2 = -160;
dist = 500;
dist2 = 550;
}
function draw() {
noStroke();
fill(0x02, 0x02, 0x1A, 10);
rect(0, 0, width, height);
fill(random(0, 255), 255, 255);
rotateBy += 0.003;
push();
translate(width/2, height/2);
rotate(rotateBy);
deg = 0;
while (deg <= 360) {
deg += incr;
ang = radians(deg);
x = cos(ang) * (rad + (dist * noise(y/100, yIn)));
y = sin(ang) * (rad + (dist * noise(x/80, yIn)));
ellipse(x, y, 1.5, 1.5);
x2 = sin(ang) * (rad2 + (dist2 * noise(y2/20, yIn)));
y2 = cos(ang) * (rad2 + (dist2 * noise(y2/20, yIn)));
ellipse(x2, y2, 1, 1);
}
yIn += 0.005;
pop();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.min.js"></script>
That looks pretty cool! Have fun !

How to draw regular geometrical shapes with a series of horizontal or vertical lines? [duplicate]

I'm trying to make this one https://massmoca.org/event/walldrawing340/
in Javascript code, using p5.js, but I have no clue how to fill these shapes with lines. Is there any other possibility, like making canvas that is circle or something like that, or I just have to make each shape seperately?
For now I was doing shape by shape, but making triangle and trapezoid is rough...
var sketch = function (p) {
with(p) {
let h,
w,
space;
p.setup = function() {
createCanvas(900, 400);
h = height / 2;
w = width / 3;
space = 10;
noLoop();
};
p.draw = function() {
drawBackground('red', 'blue', 0, 0);
shape('Circle', 'red', 'blue', 0, 0);
drawBackground('yellow', 'red', w, 0);
shape('Square', 'yellow', 'red', w, 0);
drawBackground('blue', 'yellow', 2 * w, 0);
shape('Triangle', 'blue', 'red', 2 * w, 0)
drawBackground('red', 'yellow', 0, h);
shape('Rectangle', 'red', 'blue', 0, h)
drawBackground('yellow', 'blue', w, h);
shape('Trapezoid', 'yellow', 'red', w, h);
drawBackground('blue', 'red', 2 * w, h);
};
function drawBackground(bColor, lColor, x, y) {
fill(bColor)
noStroke();
rect(x, y, w, h)
stroke(lColor);
strokeWeight(1);
for (let i = 0; i < h / space; i++) {
line(0 + x, i * space + y + 10, w + x, i * space + y + 10);
}
}
function shape(shape, bColor, lColor, x, y) {
fill(bColor)
noStroke();
let w1;
switch (shape) {
case 'Circle':
circle(x + w / 2, y + h / 2, h - space * 6);
stroke(lColor);
strokeWeight(1);
for (let i = 0; i < w / space; i++) {
for (let j = 0; j < h; j++) {
pX = i * space + x;
pY = 0 + y + j;
if (pow(x + w / 2 - pX, 2)
+ pow(pY - (y + h / 2), 2) <= pow(h - space * 6 * 2 - 10, 2)) {
point(pX, pY);
}
}
}
break;
case 'Square':
w1 = w - (h - space * 6);
rect(x + w1 / 2, y + space * 3, h - space * 6, h - space * 6);
stroke(lColor);
strokeWeight(1);
for (let i = 0; i < 15; i++) {
for (let j = 0; j < h - space * 6; j++) {
point(x + w1 / 2 + i * space, y + space * 3 + j)
}
}
break;
case 'Triangle':
w1 = w - (h - space * 6);
triangle(x + w1 / 2, h - space * 3 + y, x + w / 2, y + space * 3, x + w1 / 2 + h - space * 6, h - space * 3 + y)
for (let i = 0; i < w / space; i++) {
for (let j = 0; j < h; j++) {
pX = i * space + x;
pY = 0 + y + j;
if (pow(x + w / 2 - pX, 2)
+ pow(pY - (y + h / 2), 2) <= pow(h - space * 6 * 2 - 10, 2)) {
point(pX, pY);
}
}
}
break;
case 'Rectangle':
w1 = w - (h - space * 6) / 2;
rect(x + w1 / 2, y + space * 3, (h - space * 6) / 2, h - space * 6)
break;
case 'Trapezoid':
w1 = w - (h - space * 6);
quad(x + w1 / 2, h - space * 3 + y, x + w1 / 2 + (h - space * 6) / 4, y + space * 3, x + w1 / 4 + h - space * 6, y + space * 3, x + w1 / 2 + h - space * 6, h - space * 3 + y)
break;
case 'Parallelogram':
w1 = w - (h - space * 6);
quad(x + w1 / 4, h - space * 3 + y, x + w1 / 2, y + space * 3, x + w1 / 2 + h - space * 6, y + space * 3, x + w1 / 4 + h - space * 6, h - space * 3 + y)
break;
break;
}
}
}
};
let node = document.createElement('div');
window.document.getElementById('p5-container').appendChild(node);
new p5(sketch, node);
body {
background-color:#efefef;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.js"></script>
<div id="p5-container"></div>
No messages, everything is working, I just want to know if I have to do so much arduous job...
If you don't need actual line coordinates (for plotting for example), I'd just make most out of createGraphics() to easily render shapes and lines into (taking advantage of the fact that get() returns a p5.Image) and p5.Image's mask() function.
Here's a basic example:
function setup() {
createCanvas(600, 300);
let w = 300;
let h = 150;
let spacing = 12;
let strokeWidth = 1;
const BLUE = color('#005398');
const YELLOW = color('#f9db44');
const RED = color('#dc1215');
bg = getLinesRect(w, h, RED, BLUE, spacing, strokeWidth, true);
fg = getLinesRect(w, h, RED, YELLOW, spacing, strokeWidth, false);
mask = getCircleMask(w, h, w * 0.5, h * 0.5, 100, 0);
image(bg, 0, 0);
image(fg, w, 0);
// render opaque mask (for visualisation only), mask() requires alpha channel
image(getCircleMask(w, h, w * 0.5, h * 0.5, 100, 255),0, h);
// apply mask
fg.mask(mask);
// render bg + masked fg
image(bg, w, h);
image(fg, w, h);
// text labels
noStroke();
fill(255);
text("bg layer", 9, 12);
text("fg layer", w + 9, 12);
text("mask", 9, h + 12);
text("bg + masked fg", w + 9, h + 12);
}
function getLinesRect(w, h, bg, fg, spacing, strokeWidth, isHorizontal){
let rect = createGraphics(w, h);
rect.background(bg);
rect.stroke(fg);
rect.strokeWeight(strokeWidth);
if(isHorizontal){
for(let y = 0 ; y < h; y += spacing){
rect.line(0, y + strokeWidth, w, y + strokeWidth);
}
}else{
for(let x = 0 ; x < w; x += spacing){
rect.line(x + strokeWidth, 0, x + strokeWidth, h);
}
}
// convert from p5.Graphics to p5.Image
return rect.get();
}
function getCircleMask(w, h, cx, cy, cs, opacity){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0, opacity);
mask.noStroke();
mask.fill(255);
mask.circle(cx, cy, cs);
// convert p5.Graphics to p5.Image
return mask.get();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
You can apply the same logic for the rest of the shapes:
function setup() {
createCanvas(1620, 590);
let compWidth = 500;
let compHeight = 250;
let compSpacing= 30;
let lineWeight = 1.5;
let lineSpacing = 12;
const BLUE = color('#005398');
const YELLOW = color('#f9db44');
const RED = color('#dc1215');
// yellow square
circleMask = getCircleMask(compWidth, compHeight, compWidth * 0.5, compHeight * 0.5, 210);
redCircle = getComposition(compWidth, compHeight, RED,
BLUE,
YELLOW,
lineSpacing, lineWeight, circleMask);
// red box
boxMask = getRectMask(compWidth, compHeight, (compWidth - 100) * 0.5, 20, 100, 210);
redBox = getComposition(compWidth, compHeight, RED,
YELLOW,
BLUE,
lineSpacing, lineWeight, boxMask);
// yellow square
squareMask = getRectMask(compWidth, compHeight, 144, 20, 210, 210);
yellowSquare = getComposition(compWidth, compHeight, YELLOW,
RED,
BLUE,
lineSpacing, lineWeight, squareMask);
// yellow trapeze
trapezeMask = getQuadMask(compWidth, compHeight, 200, 25, 200 + 115, 25,
150 + 220, 220, 150, 220);
yellowTrapeze = getComposition(compWidth, compHeight, YELLOW,
BLUE,
RED,
lineSpacing, lineWeight, trapezeMask);
// blue triangle
triangleMask = getTriangleMask(compWidth, compHeight, compWidth * 0.5, 25,
150 + 220, 220, 150, 220);
blueTriangle = getComposition(compWidth, compHeight, BLUE,
YELLOW,
RED,
lineSpacing, lineWeight, triangleMask);
// blue parallelogram
parallelogramMask = getQuadMask(compWidth, compHeight, 200, 25, 200 + 145, 25,
150 + 145, 220, 150, 220);
blueParallelogram = getComposition(compWidth, compHeight, BLUE,
RED,
YELLOW,
lineSpacing, lineWeight, parallelogramMask);
// render compositions
image(redCircle, compSpacing, compSpacing);
image(redBox, compSpacing, compSpacing + (compHeight + compSpacing));
image(yellowSquare, compSpacing + (compWidth + compSpacing), compSpacing);
image(yellowTrapeze, compSpacing + (compWidth + compSpacing), compSpacing + (compHeight + compSpacing));
image(blueTriangle, compSpacing + (compWidth + compSpacing) * 2, compSpacing);
image(blueParallelogram, compSpacing + (compWidth + compSpacing) * 2, compSpacing + (compHeight + compSpacing));
}
function getComposition(w, h, bgFill, bgStroke, fgStroke, spacing, strokeWidth, mask){
let comp = createGraphics(w, h);
bg = getLinesRect(w, h, bgFill, bgStroke, spacing, strokeWidth, true);
fg = getLinesRect(w, h, bgFill, fgStroke, spacing, strokeWidth, false);
// apply mask
fg.mask(mask);
// render to final output
comp.image(bg, 0, 0);
comp.image(fg, 0, 0);
return comp;
}
function getRectMask(w, h, rx, ry, rw, rh){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0,0);
mask.noStroke();
mask.fill(255);
mask.rect(rx, ry, rw, rh);
// convert p5.Graphics to p5.Image
return mask.get();
}
function getCircleMask(w, h, cx, cy, cs){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0,0);
mask.noStroke();
mask.fill(255);
mask.circle(cx, cy, cs);
// convert p5.Graphics to p5.Image
return mask.get();
}
function getQuadMask(w, h, x1, y1, x2, y2, x3, y3, x4, y4){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0,0);
mask.noStroke();
mask.fill(255);
mask.quad(x1, y1, x2, y2, x3, y3, x4, y4);
// convert p5.Graphics to p5.Image
return mask.get();
}
function getTriangleMask(w, h, x1, y1, x2, y2, x3, y3){
let mask = createGraphics(w, h);
// make background transparent (alpha is used for masking)
mask.background(0,0);
mask.noStroke();
mask.fill(255);
mask.triangle(x1, y1, x2, y2, x3, y3);
// convert p5.Graphics to p5.Image
return mask.get();
}
function getLinesRect(w, h, bg, fg, spacing, strokeWidth, isHorizontal){
let rect = createGraphics(w, h);
rect.background(bg);
rect.stroke(fg);
rect.strokeWeight(strokeWidth);
if(isHorizontal){
for(let y = 0 ; y < h; y += spacing){
rect.line(0, y + strokeWidth, w, y + strokeWidth);
}
}else{
for(let x = 0 ; x < w; x += spacing){
rect.line(x + strokeWidth, 0, x + strokeWidth, h);
}
}
// convert from p5.Graphics to p5.Image
return rect.get();
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.1.9/p5.min.js"></script>
Probably both rectangles and the triangle could've been drawn using getQuadMask() making good use of coordinates.
Note that I've just eye balled the shapes a bit so they're not going to be perfect, but it should be easy to tweak. Bare in mind the placement of the mask will have an effect of on how the vertical lines will align.
There are probably other ways to get the same visual effect.
For example, using texture() and textureWrap(REPEAT) with beginShape()/endShape(), using pixels for each line and checking intersections before changing direction and colours, etc.
In terms of generating lines for plotting I would start with horizontal lines, doing line to convex polygon intersection to determine where to stop the horizontal lines and start vertical lines. #AgniusVasiliauskas's answer(+1) is good for that approach.
Freya Holmér has a pretty nice visual explanation for the test.
You need linear algebra stuff, basically noticing how vertical line starting/ending Y coordinate changes in relation to line's X coordinate. And of course a lot of experimenting until you get something usable. Something like :
var w = 600
h = 600
sp = 15
var slides = [fcircle, fsquare, ftriangle, ftrapezoid, fparallelogram];
var active = 0;
var ms;
function blines(){
stroke(0);
for (var i=0; i < h; i+=sp) {
line(0,i,w,i);
}
}
function vertlines(calcline) {
for (var x=w/2-w/4+sp; x < w/2+w/4; x+=sp) {
var pnts = calcline(x);
line(pnts[0],pnts[1],pnts[2],pnts[3]);
}
}
function fcircle() {
// cut background
noStroke();
circle(w/2, h/2, w/2);
stroke('red');
// draw figure lines
let calc = function (x){
var sx = x-w/2;
var sy = h/2;
var ey = h/2;
sy += 137*sin(2.5+x/135);
ey -= 137*sin(2.5+x/135);
return [x,sy,x,ey];
}
vertlines(calc);
}
function fsquare() {
// cut background
noStroke();
quad(w/2-w/4, h/2-h/4, w/2+w/4, h/2-h/4,
w/2+w/4, h/2+h/4, w/2-w/4, h/2+h/4);
stroke('red');
// draw figure lines
let calc = function (x){
return [x,h/2-h/4,x,h/2+h/4];
}
vertlines(calc);
}
function ftriangle() {
// cut background
noStroke();
quad(w/2, h/2-h/4, w/2+w/4, h/2+h/4,
w/2-w/4, h/2+h/4, w/2, h/2-h/4);
stroke('red');
// draw figure lines
let calc = function (x){
var inpx = x > w/2 ? w-x : x;
var ys = h/2+h/4;
ys += -(0.3*inpx*log(inpx)-220);
return [x,ys,x,h/2+h/4];
}
vertlines(calc);
}
function ftrapezoid() {
// cut background
noStroke();
quad(w/2-w/10, h/2-h/4, w/2+w/10, h/2-h/4,
w/2+w/4, h/2+h/4, w/2-w/4, h/2+h/4);
stroke('red');
// draw figure lines
let calc = function (x){
var inpx = x > w/2 ? w-x : x;
var ys = h/2+h/4;
ys += -(0.55*inpx*log(inpx)-420);
if (x >= w/2-w/10 && x <= w/2+w/10) {
ys=h/2-h/4;
}
return [x,ys,x,h/2+h/4];
}
vertlines(calc);
}
function fparallelogram() {
// cut background
noStroke();
quad(w/2-w/10, h/2-h/4, w/2+w/7, h/2-h/4,
w/2, h/2+h/4, w/2-w/4, h/2+h/4);
stroke('red');
// draw figure lines
let calc = function (x){
// guard condition
if (x > w/2+w/7)
return [0,0,0,0];
var inpx = x > w/2 ? w-x : x;
var ys = h/2+h/4;
ys += -(0.55*inpx*log(inpx)-420);
var ye=h/2+h/4
if (x >= w/2-w/10) {
ys=h/2-h/4;
}
if (x > w/2) {
ye = h/2+h/4;
ye += 0.50*inpx*log(inpx)-870;
}
return [x,ys,x,ye];
}
vertlines(calc);
}
function setup() {
ms = millis();
createCanvas(w, h);
}
function draw() {
if (millis() - ms > 2000) {
ms = millis();
active++;
if (active > slides.length-1)
active = 0;
}
background('#D6EAF8');
fill('#D6EAF8');
blines();
slides[active]();
}
Slideshow DEMO
I have a way to do some of the shapes, but I am not sure about others. One way you could do it is if you know where every point on the outline of the shape is, you could just use a for loop and connect every other point from the top and bottom using the line or rect function. This would be relatively easy with shapes like squares and parallelograms, but I am not sure what functions could be used to get this for the points of a circle or trapezoid.
See more here: https://www.openprocessing.org/sketch/745383

How to draw curved text using MFC functions?

How to draw curved text using MFC functions? I want to achieve like this below.
DrawText() function draws text in straight line only, I do not know how to draw curved text at particular angle. Please help me.
Thanks.
You could use GDI+, There is a sample in code project, which is written in C#, I translate it into C++:
Graphics graphics(hWnd);
RECT rect = { 0 };
GetWindowRect(hWnd, &rect);
POINT center = { (rect.right - rect.left) / 2,(rect.bottom - rect.top) / 2 };
double radius = min(rect.right - rect.left, (rect.bottom - rect.top)) / 3;
TCHAR text[] = L"ABCDEFGHIJLKMNOPQRSTUVWXYZ";
REAL emSize = 24;
Font* font = new Font(FontFamily::GenericSansSerif(), emSize, FontStyleBold);
for (int i = 0; i < _tcslen(text); ++i)
{
RectF re, in;
Status result = graphics.MeasureString(&text[i], 1, font, in, &re);;
double charRadius = radius + re.Height;
double angle = (((float)i / _tcslen(text)) - 0.25) * 2 * M_PI;
double x = (int)(center.x + cos(angle) * charRadius);
double y = (int)(center.y + sin(angle) * charRadius);
result = graphics.TranslateTransform(x, y);
result = graphics.RotateTransform((float)(90 + 360 * angle / (2 * M_PI)));
PointF start(0, 0);
SolidBrush Red(Color(255, 255, 0, 0));
result = graphics.DrawString(&text[i], 1, font, start, &Red);
result = graphics.ResetTransform();
SolidBrush Green(Color(255, 0, 255, 0));
Pen* pen = new Pen(&Green, 2.0f);
result = graphics.DrawArc(pen, (REAL)(center.x - radius), (REAL)(center.y - radius), radius * 2, radius * 2, 0, 360);
}
Some header files:
#define _USE_MATH_DEFINES
#include <math.h>
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
using namespace Gdiplus;
#pragma comment (lib,"Gdiplus.lib")
Usage:
You must call GdiplusStartup before you create any GDI+ objects, and
you must delete all of your GDI+ objects (or have them go out of
scope) before you call GdiplusShutdown.
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
//To Do.
GdiplusShutdown(gdiplusToken);
Result:
UPDATE:
Graphics graphics(hWnd);
RECT rect = { 0 };
GetWindowRect(hWnd, &rect);
POINT center = { (rect.right - rect.left) / 2,(rect.bottom - rect.top) / 2 };
double radius = min(rect.right - rect.left, (rect.bottom - rect.top)) / 3;
TCHAR text[72][4] = { 0 };
for (int i = 0; i < 72; i++)
{
_itot((i/2)*10, text[i],10);
i++;
_tcscpy(text[i],L"");
}
REAL emSize = 8;
Font* font = new Font(FontFamily::GenericSansSerif(), emSize, FontStyleBold);
for (int i = 0; i < 72; ++i)
{
RectF re, in,rel;
Status result = graphics.MeasureString(text[i], _tcslen(text[i]), font, in, &re);
result = graphics.MeasureString(L"|", 1, font, in, &rel);
double charRadius = radius - re.Height;
double angle = (((float)i / 72) - 0.25) * 2 * M_PI;
double x = (center.x + cos(angle) * charRadius);
double y = (center.y + sin(angle) * charRadius);
result = graphics.TranslateTransform(x, y);
result = graphics.RotateTransform((float)(90 + 360 * angle / (2 * M_PI)));
PointF start(0- re.Width/2, 0);
SolidBrush Red(Color(255, 255, 0, 0));
result = graphics.DrawString(text[i], _tcslen(text[i]), font, start, &Red);
result = graphics.ResetTransform();
x = (int)(center.x + cos(angle) * radius);
y = (int)(center.y + sin(angle) * radius);
result = graphics.TranslateTransform(x, y);
result = graphics.RotateTransform((float)(90 + 360 * angle / (2 * M_PI)));
PointF start1(0 - rel.Width / 2, 0);
result = graphics.DrawString(L"|", 1, font, start1, &Red);
result = graphics.ResetTransform();
}
SolidBrush Green(Color(255, 0, 255, 0));
Pen* pen = new Pen(&Green, 2.0f);
Status result = graphics.DrawArc(pen, (REAL)(center.x - radius), (REAL)(center.y - radius), radius * 2, radius * 2, 0, 360);
Result:

Does MinGW influence compilation -- a GTK program

I compiled a GTK program in MinGW environment. It worked perfect. Recently, I updated MinGW and recompiled the GTK program, then the program always stopped with Segmentation fault. I have tried to use gdb to look for errors but I couldn't. The config of GTK is exactly same in the old and new MinGW. Therefore, I am suspicious of MinGW environment that influences compilation. I found the version of gcc is different in two environment:
old MinGW new MinGW
gcc 3.4.5 4.7.2
Any idea? Does anybody meet the situation?
Another clue is about GTK itself. I found the program stopped here:
g_signal_emit_by_name(G_OBJECT(g_object_get_data(G_OBJECT(window), "plat_GA_canvas")), "expose-event", G_TYPE_NONE);
It is a canvas to draw a image according to different situation. Here it just sends a signal to expose the canvas. The curious thing is that it worked in the old MinGW. So I don't doubt it is the point of the problem. Just maybe a clue. By the way, I compiled the GTK program in a pure Linux environment at home. It also worked perfect.
Any idea? Please help.
#duskast, below is the part of the code. It is a little lengthy.
+++++++++++++++++++++++++++++++++++++++++++++++++++
The problem maybe happened -- g_signal_emit_by_name:
void ACC_platform_unit_num_changed (GtkWidget *box, GtkWidget *window)
{
int kind;
kind = gtk_option_menu_get_history((GtkOptionMenu *)box) + 1;
if(plat.unit_num != kind)
{
plat_GA_canvas_refresh (window);
g_signal_emit_by_name(G_OBJECT(g_object_get_data(G_OBJECT(window), "plat_GA_canvas")), "expose-event", G_TYPE_NONE);
plat.unit_num = kind;
if(plat.unit_num == 1)
{
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_gap"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_big_gap"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_gap_w"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_live_load_gap"), FALSE);
}
else
{
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_gap"), TRUE);
if(plat.has_gap)
{
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_big_gap"), TRUE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_gap_w"), TRUE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_live_load_gap"), TRUE);
}
else
{
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_if_big_gap"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_gap_w"), FALSE);
gtk_widget_set_sensitive(g_object_get_data(G_OBJECT(window), "ACC_platform_live_load_gap"), FALSE);
}
}
gap_span_show (g_object_get_data(G_OBJECT(window), "ACC_platform_gap_span_store"));
}
}
The core drawing function:
void ACC_GA_draw (cairo_t *cr, int width, int height)
{
/* #define X_MARGIN 30
#define Y_MARGIN 30 */
#define COLUMN_RADIUS_ASSUME 1.6
#define COLUMN_SQUARE_LEN_ASSUME 2.0
double x, y, x1, y1, x2, y2, scale, x_base, y_base, X_MARGIN, Y_MARGIN;
double x3, y3, downward_height = 0, downward_width = 0;
double x_one_unit, y_one_unit, x_total, y_total, gap_value;
double alpha = 60.0, arrow_side_length = 20.0, arrow_tail_length = 10.0;
ACC_AXIS *x_axis, *y_axis;
int i, j, unit_num, downward;
char *AX, *AY, *Wx_left, *Wx_right, *Wy_top, *Wy_bottom, *gap, *axis;
cairo_text_extents_t te;
AX = g_strdup_printf("%.0f", plat.fan_section_AX * 1000);
AY = g_strdup_printf("%.0f", plat.fan_section_AY * 1000);
Wx_left = g_strdup_printf("%.0f", plat.walkway_Wx_left * 1000);
Wx_right = g_strdup_printf("%.0f", plat.walkway_Wx_right * 1000);
Wy_bottom = g_strdup_printf("%.0f", plat.walkway_Wy_bottom * 1000);
Wy_top = g_strdup_printf("%.0f", plat.walkway_Wy_top * 1000);
x_one_unit = plat.fan_section_AX * plat.SDD_num;
x_total = x_one_unit * plat.unit_num + plat.gap_total + plat.walkway_Wx_left + plat.walkway_Wx_right;
y_one_unit = plat.fan_section_AY * plat.row_num;
y_total = y_one_unit + plat.walkway_Wy_bottom + plat.walkway_Wy_top;
scale = calcu_scale (width, height, x_total, y_total, Wx_left, Wy_top, cr, &X_MARGIN, &Y_MARGIN);
cairo_set_line_width (cr, NORMAL_LINE_WIDTH * 0.7);
for(unit_num = 1; unit_num <= plat.unit_num; unit_num++)
{
if(unit_num == 1)
x_base = X_MARGIN;
else
{
double total_gap = 0;
for(i = 0; i < unit_num - 1; i++)
total_gap += strtod(g_list_nth(plat.gap_w, i)->data, NULL);
x_base = X_MARGIN + (x_one_unit * (unit_num - 1) + total_gap) * scale;
}
y_base = Y_MARGIN;
for(i = 0, x_axis = plat.X_axis; x_axis; x_axis = x_axis->next, i++)
{
if(i == 0)
x = x_base;
else
x += plat.fan_section_AX * scale;
y = y_base;
cairo_move_to(cr, x, y);
y += y_one_unit * scale;
cairo_line_to(cr, x, y); /* vertical grid */
cairo_stroke(cr);
/* SDD */
if(i != plat.SDD_num)
{
cairo_arrow (cr, x + plat.fan_section_AX / 2 * scale, y + plat.walkway_Wy_bottom * scale, alpha, arrow_side_length, 1, arrow_tail_length);
cairo_save(cr);
cairo_set_line_width (cr, BOLD_LINE_WIDTH);
cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
cairo_move_to(cr, x_base + plat.fan_section_AX / 2 * scale, y + plat.walkway_Wy_bottom * scale + arrow_side_length + arrow_tail_length);
cairo_rel_line_to(cr, (x_one_unit - plat.fan_section_AX) * scale, 0);
cairo_stroke(cr);
cairo_restore(cr);
}
/* dim line for A1, A2 ... */
cairo_move_to(cr, x, y + plat.walkway_Wy_bottom * scale + arrow_side_length + arrow_tail_length + 10);
cairo_rel_line_to(cr, 0, 20);
cairo_get_current_point(cr, &x3, &y3);
if(i != plat.SDD_num)
{
cairo_text_align_horizontal_center (cr, AX, 0, 1, plat.fan_section_AX / 2 * scale, -10);
}
else
{
if(plat.unit_num > 1 && plat.has_gap && unit_num != plat.unit_num)
{
gap_value = strtod(g_list_nth(plat.gap_w, unit_num - 1)->data, NULL);
gap = g_strdup_printf("%.0f", 1000 * gap_value);
cairo_text_extents(cr, gap, &te);
if(gap_value * scale < te.x_bearing + te.width)
{
downward = 1;
downward_height = 11;
downward_width = gap_value * scale;
cairo_rel_move_to(cr, gap_value / 2 * scale - (te.x_bearing + te.width / 2), 10);
}
else
{
downward = 0;
cairo_rel_move_to(cr, gap_value / 2 * scale - (te.x_bearing + te.width / 2), -10);
}
cairo_show_text(cr, gap);
g_free(gap);
}
else
downward = 0;
}
if(unit_num == 1 && i == 0)
{
cairo_move_to(cr, x - plat.walkway_Wx_left * scale, y + plat.walkway_Wy_bottom * scale + arrow_side_length + arrow_tail_length + 10);
cairo_rel_line_to(cr, 0, 20);
cairo_rel_move_to(cr, -25, -10);
cairo_show_text(cr, Wx_left);
}
if(unit_num == plat.unit_num && i == plat.SDD_num)
{
cairo_move_to(cr, x + plat.walkway_Wx_right * scale, y + plat.walkway_Wy_bottom * scale + arrow_side_length + arrow_tail_length + 10);
cairo_rel_line_to(cr, 0, 20);
cairo_rel_move_to(cr, 3, -10);
cairo_show_text(cr, Wx_right);
}
if(plat.axis_style_SDD == 0) /* 递增 */
axis = g_strdup_printf("A%d", plat.start_axis_SDD + (unit_num - 1) * (plat.SDD_num + 1) + i);
else
axis = g_strdup_printf("A%d", plat.start_axis_SDD + (unit_num - 1) * (plat.SDD_num + 1) - i);
cairo_text_extents(cr, axis, &te);
if(!downward || ((i != plat.SDD_num) && (unit_num != 1 && i != 0)))
cairo_move_to(cr, x3 - te.width / 2, y3 + te.height + 2);
else
{
if(te.width < downward_width)
cairo_move_to(cr, x3 - te.width / 2, y3 + te.height + downward_height);
else
{
if(i == plat.SDD_num)
cairo_move_to(cr, x3 - te.width, y3 + te.height + downward_height);
else
cairo_move_to(cr, x3, y3 + te.height + downward_height);
}
}
cairo_show_text(cr, axis);
g_free(axis);
cairo_stroke(cr);
for(j = 0, y_axis = plat.Y_axis; y_axis; y_axis = y_axis->next, j++)
{
x1 = x_base;
if(j == 0)
y1 = y_base + y_one_unit * scale;
else
y1 -= plat.fan_section_AY * scale;
if(i == 0)
{
cairo_move_to(cr, x1, y1);
x1 += x_one_unit * scale;
cairo_line_to(cr, x1, y1); /* horizontal grid */
cairo_stroke(cr);
}
if(i != plat.SDD_num && j != plat.row_num) /* fan ring */
{
cairo_arc(cr, x + plat.fan_section_AX / 2 * scale, y1 - plat.fan_section_AY / 2 * scale, plat.fan_ring_opening_D / 2 * scale, 0, 2 * PI);
cairo_stroke(cr);
}
/* columns */
if(plat.col_type == 0) /* 砼悬臂住 */
{
if(plat.SDD_num % 2 == 0)
{
if((i + 1) % 2 == plat.SDD_col_first && (j + 1) % 2 == plat.row_col_first)
{
cairo_arc(cr, x, y1, COLUMN_RADIUS_ASSUME * scale, 0, 2 * PI);
cairo_fill(cr);
cairo_stroke(cr);
}
}
else
{
if(!plat.if_unit_symmetry || unit_num % 2 == 1)
{
if((i + 1) % 2 == plat.SDD_col_first && (j + 1) % 2 == plat.row_col_first)
{
cairo_arc(cr, x, y1, COLUMN_RADIUS_ASSUME * scale, 0, 2 * PI);
cairo_fill(cr);
cairo_stroke(cr);
}
}
else
{
if((i) % 2 == plat.SDD_col_first && (j + 1) % 2 == plat.row_col_first)
{
cairo_arc(cr, x, y1, COLUMN_RADIUS_ASSUME * scale, 0, 2 * PI);
cairo_fill(cr);
cairo_stroke(cr);
}
}
}
}
else if(plat.col_type == 1) /* 钢柱 */
{
cairo_save(cr);
cairo_set_line_width (cr, 2 * NORMAL_LINE_WIDTH);
cairo_move_to(cr, x, y1 - COLUMN_SQUARE_LEN_ASSUME / 2 * scale);
cairo_rel_line_to(cr, 0, COLUMN_SQUARE_LEN_ASSUME * scale);
cairo_move_to(cr, x - COLUMN_SQUARE_LEN_ASSUME / 2 * scale, y1 - COLUMN_SQUARE_LEN_ASSUME / 2 * scale);
cairo_rel_line_to(cr, COLUMN_SQUARE_LEN_ASSUME * scale, 0);
cairo_move_to(cr, x - COLUMN_SQUARE_LEN_ASSUME / 2 * scale, y1 + COLUMN_SQUARE_LEN_ASSUME / 2 * scale);
cairo_rel_line_to(cr, COLUMN_SQUARE_LEN_ASSUME * scale, 0);
cairo_stroke(cr);
cairo_restore(cr);
}
else if(plat.col_type == 2) /* 砼框架柱 */
{
cairo_rectangle(cr, x - COLUMN_SQUARE_LEN_ASSUME / 2 * scale, y1 - COLUMN_SQUARE_LEN_ASSUME / 2 * scale, COLUMN_SQUARE_LEN_ASSUME * scale, COLUMN_SQUARE_LEN_ASSUME * scale);
cairo_fill(cr);
cairo_stroke(cr);
}
/* dim line of AA, AB ... */
if(unit_num == plat.unit_num && i == 0)
{
cairo_move_to(cr, x1 + plat.walkway_Wx_right * scale + 10, y1);
cairo_rel_line_to(cr, 20, 0);
if(j != plat.row_num)
{
cairo_text_align_horizontal_center (cr, AY, 1, 1, -10, -plat.fan_section_AY / 2 * scale);
}
if(j == 0)
{
x2 = x1 + plat.walkway_Wx_right * scale + 10 + 20 - 5;
y2 = y1 + plat.walkway_Wy_bottom * scale;
cairo_move_to(cr, x1 + plat.walkway_Wx_right * scale + 10, y1);
cairo_rel_move_to(cr, 0, plat.walkway_Wy_bottom * scale);
cairo_rel_line_to(cr, 20, 0);
cairo_rel_move_to(cr, -10, 25);
cairo_save(cr);
cairo_rotate(cr, - PI / 2.0);
cairo_show_text(cr, Wy_bottom);
cairo_restore(cr);
}
if(j == plat.row_num)
{
cairo_move_to(cr, x1 + plat.walkway_Wx_right * scale + 10, y1);
cairo_rel_move_to(cr, 0, -plat.walkway_Wy_top * scale);
cairo_rel_line_to(cr, 20, 0);
cairo_rel_move_to(cr, -10, -1);
cairo_save(cr);
cairo_rotate(cr, - PI / 2.0);
cairo_show_text(cr, Wy_top);
cairo_restore(cr);
}
cairo_stroke(cr);
}
else if(unit_num == 1 && i == 0)
{
if(plat.axis_style_row == 0) /* 递增 */
axis = g_strdup_printf("A%c", plat.start_axis_row + j);
else
axis = g_strdup_printf("A%c", plat.start_axis_row - j);
cairo_text_extents(cr, axis, &te);
cairo_move_to(cr, x_base - plat.walkway_Wx_left * scale - 20, y1 + te.height / 2);
cairo_show_text(cr, axis);
g_free(axis);
cairo_stroke(cr);
}
}
}
}
/* walkway line */
x = X_MARGIN - plat.walkway_Wx_left * scale;
y = Y_MARGIN - plat.walkway_Wy_top * scale;
cairo_move_to(cr, x, y);
cairo_rel_line_to(cr, x_total * scale, 0);
cairo_rel_line_to(cr, 0, y_total * scale);
cairo_rel_line_to(cr, -x_total * scale, 0);
cairo_rel_line_to(cr, 0, -y_total * scale);
cairo_stroke(cr);
/* dim total line for A1, A2 ... */
cairo_move_to(cr, X_MARGIN - plat.walkway_Wx_left * scale, Y_MARGIN + (y_one_unit + plat.walkway_Wy_bottom) * scale + arrow_side_length + arrow_tail_length + 10 + 20 - 5);
cairo_rel_line_to(cr, x_total * scale, 0);
cairo_stroke(cr);
/* dim total line for AA, AB ... */
cairo_move_to(cr, x2, y2);
cairo_rel_line_to(cr, 0, -y_total * scale);
cairo_stroke(cr);
g_free(AX);
g_free(AY);
g_free(Wx_left);
g_free(Wx_right);
g_free(Wy_bottom);
g_free(Wy_top);
}
The expose-event signal:
static gboolean ACC_GA_expose (GtkWidget *canvas, GdkEventExpose *event, gpointer user_data)
{
cairo_t *cr;
cr = gdk_cairo_create (canvas->window);
if(plat.if_GA_draw)
{
ACC_GA_draw (cr, canvas->allocation.width, canvas->allocation.height);
}
else
{
char *local = char_to_utf8 ("Press button \"生成GA\" to update!!");
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 0.35);
cairo_move_to(cr, 200, 200);
cairo_show_text(cr, local);
g_free(local);
}
cairo_destroy (cr);
return FALSE;
}
In main() function:
.
.
.
canvas = gtk_drawing_area_new();
g_object_set_data(G_OBJECT(window), "plat_GA_canvas", canvas);
plat.if_GA_draw = 0;
gtk_widget_show(canvas);
gtk_box_pack_start(GTK_BOX(sub_main_box), canvas, TRUE, TRUE, 0);
g_signal_connect(G_OBJECT(canvas), "expose-event", G_CALLBACK(ACC_GA_expose), window);
.
.
.
+++++++++++++++++++++++++++++++++++++++++++++++++++
GCC 3.4.5 and GCC 4.7.2 are ABI incompatible. You need to rebuild all your code.
I found a bug in my program. The bug is that expose-event for a canvas is exposed more than once and it crashed for the second time. But I don't know why the bug didn't come up in gcc3.4.5 or in a pure Linux environment. After I revised my program, it worked for mingw-gcc4.7.2, mingw-gcc3.4.5 and a pure Linux environment.
On the other hand, gcc4.7.2 works for pre-compiled gtk2.10.11 but fails for pre-compiled gtk2.24.10 in my situation. This is maybe due to ABI issue.
I have posted 2 other posts: gtk window moved then crash and compile GTK+ in MinGW, but failed. They are more or less related with this post.

Resources