How to draw curved text using MFC functions? - winapi

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:

Related

Can you create numbers around the analog clock?

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

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 remove edge of house using opencv

How to remove the circle content of above image. The original image is showed below:
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <cmath>
#include <iostream>
using namespace cv;
using namespace std;
/**
* Helper function to find a cosine of angle between vectors
* from pt0->pt1 and pt0->pt2
*/
static double angle(cv::Point pt1, cv::Point pt2, cv::Point pt0)
{
double dx1 = pt1.x - pt0.x;
double dy1 = pt1.y - pt0.y;
double dx2 = pt2.x - pt0.x;
double dy2 = pt2.y - pt0.y;
return (dx1*dx2 + dy1*dy2) / sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10);
}
/**
* Helper function to display text in the center of a contour
*/
void setLabel(cv::Mat& im, const std::string label, std::vector<cv::Point>& contour)
{
int fontface = cv::FONT_HERSHEY_SIMPLEX;
double scale = 0.4;
int thickness = 1;
int baseline = 0;
cv::Size text = cv::getTextSize(label, fontface, scale, thickness, &baseline);
cv::Rect r = cv::boundingRect(contour);
cv::Point pt(r.x + ((r.width - text.width) / 2), r.y + ((r.height + text.height) / 2));
cv::rectangle(im, pt + cv::Point(0, baseline), pt + cv::Point(text.width, -text.height), CV_RGB(255, 0, 255), CV_FILLED);
cv::putText(im, label, pt, fontface, scale, CV_RGB(0, 0, 0), thickness, 8);
}
int main()
{
//cv::Mat src = cv::imread("polygon.png");
Mat src = imread("3.bmp");//2.png 3.jpg
Mat src_copy;
src.copyTo(src_copy);
resize(src, src, cvSize(0, 0), 1, 1);
cout << "src type " << src.type() << endl;
Mat mask(src.size(), src.type(), Scalar(0));
if (src.empty())
return -1;
// Convert to grayscale
cv::Mat gray;
if (src.type() != CV_8UC1)
cv::cvtColor(src, gray, CV_BGR2GRAY);
// Use Canny instead of threshold to catch squares with gradient shading
cv::Mat bw;
cv::Canny(gray, bw, 0, 50, 5);
// Find contours
std::vector<std::vector<cv::Point> > contours;
cv::findContours(bw.clone(), contours, CV_RETR_LIST, CV_CHAIN_APPROX_NONE);
drawContours(src, contours, -1, Scalar(0, 255, 0), 2);
std::vector<cv::Point> approx;
cv::Mat dst = src.clone();
for (int i = 0; i < contours.size(); i++)
{
// Approximate contour with accuracy proportional
// to the contour perimeter
cv::approxPolyDP(cv::Mat(contours[i]), approx, cv::arcLength(cv::Mat(contours[i]), true)*0.1, true);
// Skip small or non-convex objects
if (std::fabs(cv::contourArea(contours[i])) < 500 || !cv::isContourConvex(approx))
continue;
if (approx.size() == 3)
{
//setLabel(dst, "TRI", contours[i]); // Triangles
}
else if (approx.size() >= 4 && approx.size() <= 6)
{
// Number of vertices of polygonal curve
int vtc = approx.size();
// Get the cosines of all corners
std::vector<double> cos;
for (int j = 2; j < vtc + 1; j++)
cos.push_back(angle(approx[j%vtc], approx[j - 2], approx[j - 1]));
// Sort ascending the cosine values
std::sort(cos.begin(), cos.end());
// Get the lowest and the highest cosine
double mincos = cos.front();
double maxcos = cos.back();
// Use the degrees obtained above and the number of vertices
// to determine the shape of the contour
if (vtc == 4 && mincos >= -0.2 && maxcos <= 0.5)
{
Mat element = getStructuringElement(MORPH_RECT, Size(13, 13));
setLabel(dst, "RECT", contours[i]);
drawContours(mask, contours, i, Scalar(255, 255, 255), CV_FILLED);
dilate(mask, mask, element);
src_copy = src_copy - mask;
}
else if (vtc == 5 && mincos >= -0.34 && maxcos <= -0.27)
setLabel(dst, "PENTA", contours[i]);
else if (vtc == 6 && mincos >= -0.55 && maxcos <= -0.45)
setLabel(dst, "HEXA", contours[i]);
}
else
{
// Detect and label circles
double area = cv::contourArea(contours[i]);
cv::Rect r = cv::boundingRect(contours[i]);
int radius = r.width / 2;
if (std::abs(1 - ((double)r.width / r.height)) <= 0.2 &&
std::abs(1 - (area / (CV_PI * std::pow(radius, 2)))) <= 0.2)
setLabel(dst, "CIR", contours[i]);
}
}
//cv::imshow("src", src);
imwrite("mask.jpg", mask);
imwrite("src.jpg", src_copy);
imwrite("dst.jpg", dst);
cv::imshow("dst", dst);
cv::waitKey(0);
return 0;
}

How to draw a dotted line using OpenGL ES 1?

To draw a dotted line in OpenGL I can use glLineStipple, but how do I achieve the same effect in OpenGL ES 1?
Lines can be textured, just like triangles. Enable alpha testing, apply an alpha texture, set up some texture coordinates, and enjoy.
Actually i have realized the doted line or the dashed line using for loops but it still make non sense to use it as a line type link to the drawing method, here is the code of my doted line and dashed line below:
doted line:
(void)drawVerticalDotedInternalGrid{
float a,b;
int drawCount =0;
GLfloat dotedInternalGrid[1296];
for (a = -0.5f; a <= 0.5f; a +=0.5f) {
for (b = -0.875f; b <=0.925f; b += 0.025f)
{
dotedInternalGrid[drawCount] = b;
drawCount++;
dotedInternalGrid[drawCount] = a;
drawCount++;
};
};
glPointSize(1.0f);
glColor4f(0.863f,0.863f,0.863f,0.8f); //line color
glVertexPointer(2, GL_FLOAT, 0, dotedInternalGrid);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_POINTS, 0, 648);
glDisableClientState(GL_VERTEX_ARRAY);
}
dashed line:
(void)drawVerticalDashedInternalGridH{
GLfloat dashedLine[1296];
float a,b;
int i =0;
//-0.4----0.4 // -0.875----0.900
for (a = -0.4f; a <= 0.4f; a +=0.1f) {
for (b =-0.825f; b <=0.950f; b+=0.025f) {
dashedLine[i] = b;
i++;
dashedLine[i] = a;
i++;
};
};
//glLineWidth(1.0f);
glColor4f(0.863f,0.863f,0.863f,1.f); //line color
glVertexPointer(2, GL_FLOAT, 0, dashedLine);
glEnableClientState(GL_VERTEX_ARRAY);
glDrawArrays(GL_LINES, 0, 648);
glDisableClientState(GL_VERTEX_ARRAY);
}
of course ye can see the code is drawing in a rectangle area of certain coordinates,the bother things is how to figure out the dotedInternalGrid[1296]; this size of array dynamically for draw method use and the number of lines to draw as well.
To explain it easily, I have put drawHorizontalDashedLine() first.
To understand, click this image.
I cannot put an image on this post because of my reputation.
Visualizing the Vertices
+(void)drawHorizontalDashedLine:(GLfloat)x1 x2:(GLfloat)x2 y:(GLfloat)y {
//Parameters
GLfloat DASH_LENGTH = 4.0f;
GLfloat GAP_LENGTH = 2.0f;
GLfloat LINE_THICKNESS = 1.5f;
//Calculate how many dashes require to draw the whole line
GLfloat fHorizontalLength = fabsf(x2-x1);
int nDashedLineCount = fHorizontalLength / (DASH_LENGTH + GAP_LENGTH);
int nVerticesSize = nDashedLineCount * 4; //A dashed line has 4 values(2 points)
//Vertex
GLfloat vertices[nVerticesSize];
//The first dashed line vertices
vertices[0] = (x1 < x2)? x1 : x2;
vertices[1] = y;
vertices[2] = (x1 < x2)? x1 : x2 + DASH_LENGTH;
vertices[3] = y;
//The other vertices of dashed lines
for (int nIndex=4; nIndex < nVerticesSize; nIndex=nIndex+4) {
vertices[nIndex] = vertices[nIndex-2] + GAP_LENGTH;
vertices[nIndex+1] = y;
vertices[nIndex+2] = vertices[nIndex] + DASH_LENGTH;
vertices[nIndex+3] = y;
//NSLog(#"Point1(%.2f, %.2f)", vertices[nIndex], vertices[nIndex+1]);
//NSLog(#"Point2(%.2f, %.2f)", vertices[nIndex+2], vertices[nIndex+3]);
}
//Draw the arrays
glPushMatrix();
glLineWidth(LINE_THICKNESS);
glVertexPointer (2, GL_FLOAT, 0, vertices);
glDrawArrays (GL_LINES, 0, nVerticesSize/2);
glPopMatrix();
}
drawDashedLine().
I used the trigonometric function to get lengths.
+(void)drawDashedLine:(CGPoint)point1 point2:(CGPoint)point2 {
//Parameters
GLfloat DASH_LENGTH = 3.0f;
GLfloat GAP_LENGTH = 1.0f;
GLfloat LINE_THICKNESS = 1.5f;
//Calculate how many dashes require to draw the whole line
GLfloat fWidth = point2.x - point1.x;
GLfloat fHeight = point2.y - point1.y;
GLfloat fRadian = atan2(fHeight, fWidth);
float fLineLength = sqrtf(powf(fWidth, 2) + powf(fHeight, 2));
int nDashedLineCount = fabsf(fLineLength / (DASH_LENGTH + GAP_LENGTH));
int nVerticesSize = nDashedLineCount * 4; //A dashed line has 4 values(2 points)
//Vertex
GLfloat vertices[nVerticesSize];
//The first dashed line vertices
vertices[0] = point1.x;
vertices[1] = point1.y;
vertices[2] = point1.x + cosf(fRadian) * DASH_LENGTH;
vertices[3] = point1.y + sinf(fRadian) * DASH_LENGTH;
//The other vertices of dashed lines
for (int nIndex=4; nIndex < nVerticesSize; nIndex=nIndex+4) {
vertices[nIndex] = vertices[nIndex-2] + cosf(fRadian) * GAP_LENGTH;
vertices[nIndex+1] = vertices[nIndex-1] + sinf(fRadian) * GAP_LENGTH;
vertices[nIndex+2] = vertices[nIndex] + cosf(fRadian) * DASH_LENGTH;
vertices[nIndex+3] = vertices[nIndex+1] + sinf(fRadian) * DASH_LENGTH;
//NSLog(#"DrawDash Point1(%.2f, %.2f)", vertices[nIndex], vertices[nIndex+1]);
//NSLog(#"DrawDash Point2(%.2f, %.2f)", vertices[nIndex+2], vertices[nIndex+3]);
}
//Draw the arrays
glPushMatrix();
glLineWidth(LINE_THICKNESS);
glVertexPointer (2, GL_FLOAT, 0, vertices);
glDrawArrays (GL_LINES, 0, nVerticesSize/2);
glPopMatrix();
}
glPushAttrib(GL_ENABLE_BIT);
# glPushAttrib is done to return everything to normal after drawing
glLineStipple(1, 0xAAAA); # [1]
glEnable(GL_LINE_STIPPLE);
glBegin(GL_LINES);
glVertex3f(-.5,.5,-.5);
glVertex3f(.5,.5,-.5);
glEnd();
glPopAttrib();

Resources