Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 54b9b4d

Browse files
committed
Added qmlRayTracing2D to the repository. Added README files for everybody!
1 parent 08ab18e commit 54b9b4d

File tree

23 files changed

+439
-17
lines changed

23 files changed

+439
-17
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Demo | Description | Screenshot
1212
**cvVideo** | A C++/OpenCV/Qt example on how to display video files with configurable Aspect Ratio. | <img src="cvVideo/screenshot.gif" width="200"/>
1313
**cvWatershedSegmentation** | [Stackoverflow answer](https://stackoverflow.com/a/25851951/176769) that uses C++/OpenCV's watershed segmentation with distance transform to segment beans. | <img src="cvWatershedSegmentation/screenshot.jpg" width="200"/>
1414
**ipcQtGesture** | A C++/Qt application that uses the old *Intel® Perceptual Computing SDK 2013* for gesture recognition. Windows only. | No image available
15+
**qmlRayTracing2D** | A QML implementation of 2D raycasting from [Daniel Shiffman](https://www.youtube.com/watch?v=TOEi6T2mtHo). | <img src="qmlRayTracing2D/screenshot.gif" width="200"/>
1516
**qmlBattery** | A Qt/QML Battery element that displays the amount of energy left as horizontal bars according to the charge. On this demo, the charge is set dynamically and randomly from the C++ side. | <img src="qmlBattery/screenshot.gif" width="200"/>
1617
**qtArduinoSerial** | An C++/Qt example on how to print data from a serial (COM) port connected to Arduino. | No image available
1718
**qtFPSvsTIMEAnimation** | A C++/Qt implementation of FPS-based and Time-based animation techniques, as explained by [Steven Lambert](http://blog.sklambert.com/using-time-based-animation-implement/) | <img src="qtFPSvsTIMEAnimation/screenshot.gif" width="180"/>

cvDisplacementMapFilter/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# cvDisplacementMapFilter
2+
3+
<img src="screenshot.gif" alt="Screenshot" width="300" height="230">

cvFruitClassification/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# cvFruitClassification
2+
3+
<img src="screenshot.jpg" alt="Screenshot" width="250" height="250">

cvImage/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# cvImage
2+
3+
<img src="screenshot.jpg" alt="Screenshot" width="413" height="323">

cvQtCameraGL/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# cvQtCameraGL
2+
3+
<img src="screenshot.gif" alt="Screenshot" width="250" height="207">

cvVideo/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# cvVideo
2+
3+
<img src="screenshot.gif" alt="Screenshot" width="400" height="184">

cvWatershedSegmentation/README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# cvWatershedSegmentation
2+
3+
<img src="screenshot.jpg" alt="Screenshot" width="256" height="256">

qmlBattery/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ Battery {
1616

1717
Screenshot
1818
--------------
19-
<img src="screenshot.jpg" alt="Screenshot" width="427" height="330">
19+
<img src="screenshot.gif" alt="Screenshot" width="300" height="300">
2020

2121

2222

qmlRayTracing2D/Boundary.qml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import QtQuick 2.0
2+
import "draw.js" as Draw
3+
4+
Item {
5+
property vector2d a: Qt.vector2d(0, 0)
6+
property vector2d b: Qt.vector2d(0, 0)
7+
8+
function show(ctx) {
9+
Draw.line(ctx, a.x, a.y, b.x, b.y, Qt.rgba(255, 255, 255, 1));
10+
11+
//console.log("Boundary.show: a=" + a);
12+
//console.log("Boundary.show: b=" + b);
13+
}
14+
15+
Component.onCompleted: {
16+
console.log("Boundary constructed: a=" + a + " b=" + b);
17+
}
18+
}

qmlRayTracing2D/Particle.qml

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/* Particle
2+
* A component that represents a particle that emits light in all directions.
3+
*/
4+
import QtQuick 2.12
5+
import "draw.js" as Draw
6+
7+
Item {
8+
id: particle
9+
10+
property var pos: Qt.vector2d(0, 0)
11+
property var rays: createListOfRays()
12+
property var numRays: 30; // the amount of light rays that this particle emits
13+
14+
function show(ctx) {
15+
Draw.circle(ctx, pos.x, pos.y, 4, "white");
16+
17+
for (let i = 0; i < rays.length; ++i)
18+
rays[i].show(ctx);
19+
}
20+
21+
// createListOfRays: returns a list of QML components of type Ray
22+
function createListOfRays() {
23+
var list = new Array(numRays);
24+
const incSize = 360 / numRays;
25+
26+
for (let i = 0, x = 0; i < 360; i += incSize, ++x) {
27+
var component = Qt.createComponent("Ray.qml");
28+
if (component === null) {
29+
// Error Handling
30+
console.log("Particle !!! error creating component");
31+
console.log(component.errorString());
32+
return;
33+
}
34+
35+
const radians = degToRad(i)
36+
//console.log("Particle: i=" + i + " radians=" + radians);
37+
38+
// invoke the constructor of Boundary with the following parameters (property binding is used for Ray.pos)
39+
var options = {
40+
"pos": Qt.binding(function(){ return particle.pos; }),
41+
"angle": radians
42+
};
43+
var dynamicRay = component.createObject(particle, options);
44+
45+
if (dynamicRay === null) {
46+
console.log("Particle !!! error creating object");
47+
console.log(component.errorString());
48+
return;
49+
}
50+
51+
list[x] = dynamicRay;
52+
}
53+
54+
//console.log("Particle: createListOfRays list sz=" + list.length);
55+
return list;
56+
}
57+
58+
function degToRad(degrees) {
59+
return degrees * (Math.PI / 180);
60+
}
61+
62+
// lookWall: test each ray of the particle for a collision with a single wall (helpful for debugging)
63+
function lookWall(wall, ctx) {
64+
// draw rays into the direction of the wall
65+
for (let i = 0; i < rays.length; ++i) {
66+
const pt = rays[i].cast(wall);
67+
68+
// check if the point of intersection exists
69+
if (pt)
70+
Draw.line(ctx, particle.pos.x, particle.pos.y, pt.x, pt.y, "yellow");
71+
}
72+
}
73+
74+
// look: test each ray of the particle for a collision with the closest wall
75+
function look(walls, ctx) {
76+
// draw rays into the direction of the closest wall
77+
for (let i = 0; i < particle.rays.length; ++i) {
78+
const ray = particle.rays[i];
79+
let closestIntersectionPt = null;
80+
let recordDist = Number.MAX_VALUE; // Infinity
81+
82+
for (let j = 0; j < walls.length; ++j) {
83+
// figure out if this ray of light hits the wall
84+
const wall = walls[j];
85+
const pt = ray.cast(wall);
86+
87+
// check if there is an intersection point between the ray and this wall
88+
if (pt) {
89+
const dist = distance(particle.pos, pt);
90+
if (dist < recordDist) {
91+
recordDist = dist;
92+
closestIntersectionPt = pt;
93+
}
94+
}
95+
}
96+
97+
if (closestIntersectionPt)
98+
Draw.line(ctx, particle.pos.x, particle.pos.y, closestIntersectionPt.x, closestIntersectionPt.y, "yellow");
99+
}
100+
}
101+
102+
// distance: calculates the Euclidian distance between 2 points
103+
function distance(a, b) {
104+
var horizDist = a.x - b.x;
105+
var vertDist = a.y - b.y;
106+
return Math.sqrt(horizDist*horizDist + vertDist*vertDist);
107+
}
108+
109+
// update: updates the particle position in the world
110+
function update(x, y) {
111+
particle.pos.x = x;
112+
particle.pos.y = y;
113+
}
114+
}

qmlRayTracing2D/README.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
# qmlRayTracing2D
2+
3+
A naive implementation of 2D raytracing using line segment "surfaces" and vector "rays".
4+
5+
<img src="screenshot.gif" alt="Screenshot" width="400" height="400">
6+
7+
**Reference**: [The Coding Train - Coding Challenge #145: 2D Raycasting](https://www.youtube.com/watch?v=TOEi6T2mtHo)
8+

qmlRayTracing2D/Ray.qml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/* Ray
2+
* A component that represents a ray of light.
3+
* It calculates the point of interception with a wall if they collide.
4+
*/
5+
import QtQuick 2.0
6+
import "draw.js" as Draw
7+
8+
Item {
9+
id: ray
10+
11+
property var angle: 0.0 // the angle of the light in radians
12+
property vector2d pos: Qt.vector2d(0, 0) // starting position of the ray
13+
property vector2d dir: fromAngle(angle) // unit vector that guides the direction of the light
14+
15+
property var raySize: 8 // size of the ray for debugging purposes
16+
17+
// show: draw the light of ray on the screen (red)
18+
function show(ctx) {
19+
Draw.line(ctx, ray.pos.x, ray.pos.y, ray.pos.x+ray.dir.x*raySize, ray.pos.y+ray.dir.y*raySize, "red");
20+
//console.log("Ray.show: pos=" + pos + " angle=" + angle + " dir=" + dir);
21+
}
22+
23+
// fromAngle: creates a unit vector with the direction of the angle (radians)
24+
function fromAngle(rad) {
25+
return Qt.vector2d(Math.cos(rad), Math.sin(rad));
26+
}
27+
28+
// lookAt: sets the direction to where the ray is looking at
29+
function lookAt(x, y) {
30+
ray.dir.x = x - ray.pos.x;
31+
ray.dir.y = y - ray.pos.y;
32+
ray.dir = ray.dir.normalized(); // shortens the ray
33+
}
34+
35+
// cast: returns the point of intersection between two lines. Otherwise, it returns NULL.
36+
function cast(wall) {
37+
/* The intersection point falls within the first line segment if 0.0 <= t <= 1.0
38+
* AND if it falls within the second line segment if: u >= 0
39+
*/
40+
// wall endpoints
41+
var x1 = wall.a.x;
42+
var y1 = wall.a.y;
43+
var x2 = wall.b.x;
44+
var y2 = wall.b.y;
45+
//console.log("Ray::cast wall pt1=" + x1 + "," + y1 + " pt2=" + x2 + "," + y2);
46+
47+
// ray endpoints
48+
var x3 = ray.pos.x;
49+
var y3 = ray.pos.y;
50+
var x4 = ray.pos.x + ray.dir.x;
51+
var y4 = ray.pos.y + ray.dir.y;
52+
//console.log("Ray::cast ray pt1=" + x3 + "," + y3 + " pt2=" + x4 + "," + y4);
53+
54+
// calculate the denominator
55+
var den = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
56+
//console.log("den=" + den);
57+
58+
// if den is 0, it means that ray and wall are perfectly parallel to each other and will never TouchPoint
59+
if (den === 0)
60+
return {};
61+
62+
// calculate t and u
63+
var t = ((x1 - x3) * (y3 - y4) - (y1 - y3) * (x3 - x4)) / den;
64+
var u = -((x1 - x2) * (y1 - y3) - (y1 - y2) * (x1 - x3)) / den;
65+
//console.log("t=" + t);
66+
//console.log("u=" + u);
67+
68+
// if they intersect, calculate the point of intersection
69+
if (t > 0 && t < 1 && u > 0) {
70+
var pt = Qt.vector2d(0, 0);
71+
pt.x = x1 + t * (x2 - x1);
72+
pt.y = y1 + t * (y2 - y1);
73+
return pt;
74+
}
75+
76+
// otherwise, return undefined: no intersection found
77+
return {};
78+
}
79+
80+
Component.onCompleted: {
81+
console.log("Ray constructed: pos=" + pos.x + "," + pos.y + " angle=" + angle + " dir=" + dir);
82+
}
83+
}

qmlRayTracing2D/draw.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// helper functions for drawing inside Canvas
2+
3+
function line(ctx, x1, y1, x2, y2, color) {
4+
ctx.lineWidth = 1;
5+
ctx.strokeStyle = color;
6+
ctx.beginPath();
7+
ctx.moveTo(x1, y1);
8+
ctx.lineTo(x2, y2);
9+
ctx.closePath();
10+
ctx.stroke();
11+
}
12+
13+
function circle(ctx, x, y, radius, color) {
14+
ctx.fillStyle = color;
15+
ctx.strokeStyle = "transparent";
16+
ctx.arc(x, y, radius, 0, 2*Math.PI, false);
17+
ctx.fill();
18+
}
19+
20+
function rect(ctx, x, y, w, h, color) {
21+
ctx.fillStyle = color;
22+
ctx.fillRect(x, y, w, h);
23+
ctx.fill()
24+
ctx.stroke();
25+
}

qmlRayTracing2D/main.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#include <QGuiApplication>
2+
#include <QQmlApplicationEngine>
3+
4+
int main(int argc, char *argv[])
5+
{
6+
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
7+
8+
QGuiApplication app(argc, argv);
9+
10+
QQmlApplicationEngine engine;
11+
const QUrl url(QStringLiteral("qrc:/main.qml"));
12+
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
13+
&app, [url](QObject *obj, const QUrl &objUrl) {
14+
if (!obj && url == objUrl)
15+
QCoreApplication::exit(-1);
16+
}, Qt::QueuedConnection);
17+
engine.load(url);
18+
19+
return app.exec();
20+
}

0 commit comments

Comments
 (0)