Back again with my visual clock. I need a bit of guidance. I am trying to make a "clock" graph that counts down the time (in hours) until event times that a user inputs, such as until they eat dinner, sleep etc. In my sketch, "now" is the dark grey line on the left, and I would like to create a system that counts down these input times, in relation to real time. The white ticks signify 24 hrs in a day. I also want the gradient to change in relation to "now" depending on the lightness outside. Mapping was suggested, but I don't even know where to start. Here is my sketch and code: any help you be appreciated!
My Sketch in Illustrator
PFont din;
PFont din2;
color blue = color(0, 80, 200);
color orange = color(255, 150, 50);
int hr = hour();
float w, h, angle;
void setup () {
size (1100, 600, P2D);
din = loadFont("DIN-Medium-30.vlw");
din2 = loadFont("DIN-Medium-15.vlw");
}
void draw() {
background(255);
gradientRect(90, 470, 850, 50, blue, orange);
fill(0, 102, 153);
textFont(din);
if (hr > 12) {
hr=hour()-12;
text("pm", 220, 55);
} else {
text ("am", 220, 55);
}
text(nf(hr, 2)+":", 86, 55);
text(nf(minute(), 2)+":", 126, 55);
text(nf(second(), 2), 166, 55);
textFont(din2);
text("SLEEP", 25, 350);
stroke(255);
textFont(din2);
text("TEST", 25, 250);
textFont(din2);
text("DINNER", 25, 150);
//GREY RECT
strokeWeight(0);
fill(209);
rect(90, 70, 850, 400);
//DINNER
strokeWeight(2);
stroke(255);
noFill();
rect(90, 130, 850, 30);
//TEST
strokeWeight(2);
stroke(255);
noFill();
rect(90, 230, 850, 30);
//SLEEP
strokeWeight(2);
stroke(255);
noFill();
rect(90, 330, 850, 30);
//NOW
stroke(150);
strokeWeight(5);
line(90, 470, 90, 75);
//24 HRS
stroke(255);
strokeWeight(2);
translate(90, 230);
// TIME
angle = millis();
w = hr=hour()-12;
h = 30;
fill(255);
rect(0, 0, w, 100);
strokeWeight(0);
}
//Gradiant
void gradientRect(int x, int y, int w, int h, color c1, color c2) {
beginShape();
fill(c1);
vertex(x, y);
vertex(x, y+h);
fill(c2);
vertex(x+w, y+h);
vertex(x+w, y);
endShape();
}
//input, output - calculations, get second();
//map();
It's really hard to answer "how do I do this?" or "how do I start?" type questions, so they're generally considered off-topic on Stack Overflow. Stack Overflow is more for specific "I tried X, expected Y, but got Z instead" type questions.
That being said, your question is "How do I start programming a sketch like this?", and I'll try to answer that.
The golden rule to starting a programming project is: start smaller. Try to break your end goal down into much smaller individual steps, and then try to do those steps one at a time. You've already got a sketch that does the step of drawing a display, and that's great. Now create a separate sketch that only shows the current time. This might seem dumb, or smaller than what you're interested in, but that's good. That's how you start a big programming project: by breaking it down into pieces that seem too small to be interesting.
In creating these separate sketches that only do one small piece of your big main goal, the Processing reference is your best friend. Check out the Time & Date section of the reference for some useful functions. Here's a little example sketch that just shows the current time:
void draw() {
background(0);
int h = hour();
int m = minute();
int s = second();
String time = h + ":" + m + ":" + s;
text(time, 10, 50);
}
From there, it's easier for you to create a countdown timer in this small example than if you keep focusing on your big goal. Here's one that counts down until midnight:
void draw() {
background(0);
int h = 24-hour();
int m = 60-minute();
int s = 60-second();
String time = h + ":" + m + ":" + s;
text(time, 10, 50);
}
Now that you've got that working, it'll be easier to make small, incremental changes to get closer and closer to your goal. The next thing you might do is show a simple visualization of the time instead of text. Again, the reference is your best friend: the reference for the minute() function shows an example that shows the time in a simple visualization:
void draw() {
background(204);
int s = second(); // Values from 0 - 59
int m = minute(); // Values from 0 - 59
int h = hour(); // Values from 0 - 23
line(s, 0, s, 33);
line(m, 33, m, 66);
line(h, 66, h, 100);
}
And we might try to add that type of logic to our small countdown sketch. Something like this:
void draw() {
background(128);
int h = 24-hour();
int m = 60-minute();
int s = 60-second();
line(s, 0, s, 33);
line(m, 33, m, 66);
line(h, 66, h, 100);
}
From there, keep asking yourself: what is the absolute, smallest, simplest thing I know I need to do next? If something seems confusing or too big, then break it down even further. Create a bunch of tiny sketches that only do one thing, and only think about combining them when you have them working by themselves. That way, when you get stuck, you'll be able to ask more specific questions by posting the small sketch that you're stuck on.
Instead of focusing on the big picture and trying to do it all at once, break it down into smaller pieces, and focus on only one small piece at a time.
Good luck, and happy coding!
Related
I'm drawing some lines and arcs using SkiaSharp on a SKCanvasView (Xamarin.Forms) under Android 11.
I create the SKPath, and it mostly renders as expected, but I'm finding that the Close() stroke always ends at the start-point of the last-added Arc rather than at the 1st point in the path.
Code:
SKPoint pt = new SKPoint(600, 400); // Random location
float r = 100; // Arc radius
float d = 2 * r; // Side of arc rect
SKRect rc = new SKRect(pt.X, pt.Y, pt.X + d, pt.Y + d);
SKPath path = new SKPath();
path.MoveTo(rc.Right + 50, rc.Top);
path.LineTo(rc.Right, rc.MidY); // Line "S"
path.ArcTo(rc, 0, 90, true); // Arc "A"
path.ArcTo(rc, 90, 90, true); // Arc "B"
path.ArcTo(rc, 180, 90, true); // Arc "C"
path.Close(); // Line "K"
using (var skp = new SKPaint() { Style=SKPaintStyle.Stroke, IsAntialias=true, Color=SKColors.Red, StrokeWidth=6 }) {
canv.DrawPath(path, skp);
}
And here's the result (non-red items added for illustration).
The thing that I don't understand is why path.Close() causes line "K" to end at the B/C juncture rather than at the origin of "S". I would have expected Close() to generate line "G" (in red, of course) rather than "K".
Any insight would be much appreciated!
Close goes to the start of the current contour.
Instead of
path.ArcTo(rc, 0, 90, true);
You want
path.ArcTo(rc, 0, 90);
OR
path.ArcTo(rc, 0, 90, false);
Make this change on all of those ArcTo calls.
Reason:
final parameter "true" told it to start a new contour!
As described in Three ways to Draw an Arc:
public void ArcTo (SKRect oval, Single startAngle, Single sweepAngle, Boolean forceMoveTo)
That last argument is called forceMoveTo, and it effectively causes a MoveTo call at the beginning of the arc. That begins a new contour.
I am currently working on creating openGL buffers in Qt for some 3D models (cuboids of various sizes depicting buildings).
I've tried to look into some examples, but I've only found some for 2D. I tried using the same for 3D, but at best I end up with blank images when I convert my buffers to images to check.
I reached the max success (at least an image is being created) using: https://dangelog.wordpress.com/2013/02/10/using-fbos-instead-of-pbuffers-in-qt-5-2/
My current code is something like:
QOpenGLFramebufferObject* SBuildingEditorUtils::getFboForBuilding(Building bd)
{
glPushMatrix();
QSurfaceFormat format;
format.setMajorVersion(4);
format.setMinorVersion(3);
QWindow window;
window.setSurfaceType(QWindow::OpenGLSurface);
window.setFormat(format);
window.create();
QOpenGLContext context;
context.setFormat(format);
if (!context.create())
qFatal("Cannot create the requested OpenGL context!");
context.makeCurrent(&window);
// TODO: fbo size = building size
QOpenGLFramebufferObjectFormat fboFormat;
fboFormat.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
//fboFormat.setAttachment(QOpenGLFramebufferObject::Depth);
auto fbo = new QOpenGLFramebufferObject(1500, 1500, fboFormat);
auto res = glGetError();
auto bindRet = fbo->bind();
glEnable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
glOrtho(0, 1500, 0, 1500, 0, 1500);
glMatrixMode(GL_MODELVIEW);
glBegin(GL_POLYGON);
glVertex3d(500, 500, 500);
glVertex3d(500, 1000, 1000);
glVertex3d(1000, 1000, 1000);
glVertex3d(1000, 500, 500);
glEnd();
glDisable(GL_DEPTH_TEST);
fbo->toImage().save("uniqueName.png");
fbo->release();
glPopMatrix();
return fbo;
}
Here I've been using the image "uniqueName.png" to text my output. As you can guess most of the code here just for testing. Also, this code is part of a larger code base.
Any advice of what I might be missing. While I have some experience with Qt, I lack any formal education / training in openGL. Any help would be appreciated.
I wish to know how to get the code to work.
Thanks.
I want to implement cubemap convolution for IBL using a Qt widget.
When implementing conversion from an equirectangular map to a cubemap I ran into an error I do not understand:
Here is how I create my renderbuffer:
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setInternalTextureFormat(GL_RGBA32F_ARB);
envTarget = new QOpenGLFramebufferObject(QSize(256, 256), format);
Here is how I create my cubemap texture:
envCubemap = new QOpenGLTexture(QOpenGLTexture::TargetCubeMap);
envCubemap->create();
envCubemap->bind();
envCubemap->setSize(256, 256, 4);
envCubemap->setFormat(QOpenGLTexture::RGBAFormat);
envCubemap->allocateStorage(QOpenGLTexture::RGB, QOpenGLTexture::Float32);
envCubemap->setMinMagFilters(QOpenGLTexture::Nearest, QOpenGLTexture::Linear);
I then proceed to render the different cubemap views to the corresponding parts of the texture:
envCubemap->bind(9);
glViewport(0, 0, 256, 256);
envTarget->bind();
for (unsigned int i = 0; i < 6; ++i)
{
ActiveScene->ActiveCamera->View = captureViews[i];
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 9, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawBackground();
}
envTarget->release();
The drawBackground() method draws an environment sphere which works fine with my default buffer.
The openGL error I get is 1282. This turns to 0 if I comment out the glFramebufferTexture2D line. 1282 corresponds to GL_INVALID_OPERATION or GL_INVALID_VALUE, where both of these have multiple errors attached to them according to the glFramebufferTexture2D documentation.
What did I get wrong? I tried iterating over each parameter in order to solve this error but did not come up with a solution. As this should be fairly standard stuff I hope to find a solution here :D Help?
You need to actually tell the framebuffer, which texture to render to using its ID, and not '9':
glFramebufferTexture2D(
GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_TEXTURE_CUBE_MAP_POSITIVE_X + i,
envCubemap->textureId(), // <--- The change
0);
The same goes for envCubemap->bind(9);, which can be simply removed.
i am trying to create a kind of metaball, nice curves between two circles.
Something like the image, the lines are drawn straight but can also be more curved. I need them as a vector in Processing. Does anyone can help me?
thanks in advance!
Example in paperjs:
http://paperjs.org/examples/meta-balls/
image:
http://www.smeulders.biz/tmp/metaballs.png
void setup() {
size(500,500);
ellipse(100, 250, 100, 100);
ellipse(350, 250, 200, 200);
}
void draw() {}
With a bit of math (to workout distance between circles) and a bit of pixel manipulation to set pixel colours based on these calculated distances, you can render 2D metaballs and there plenty of examples
For fun however I decided to take a stab at making a very hacky version of the example you shared by simply rendering ellipses into an image, then filtering the image at the end:
PGraphics pg;//a separate layer to render into
int dilateAmt = 3;
PImage grid;//pixels of the grid alone, minus the 'cursor'
void setup(){
size(400,400);
//create a new layer
pg = createGraphics(width,height);
pg.beginDraw();
//draw a di-grid inside
pg.background(255);
pg.noStroke();pg.fill(0);
for(int y = 0 ; y < 5; y++)
for(int x = 0 ; x < 5; x++)
pg.ellipse((y%2==0?40:0)+(x * 80),40+(y * 80), 40, 40);
pg.endDraw();
//grab a snapshot for later re-use
grid = pg.get();
}
void draw(){
pg.beginDraw();
//draw the cached grid (no need to loop and re-render circles)
pg.image(grid,0,0);
//and the cursor into the layer
pg.ellipse(mouseX,mouseY,60,60);
pg.endDraw();
//since PGraphics extends PImage, you can filter, so we dilate
for(int i = 0; i < dilateAmt; i++) pg.filter(DILATE);
//finally render the result
image(pg,0,0);
}
void keyPressed(){
if(keyCode == UP) dilateAmt++;
if(keyCode == DOWN) dilateAmt--;
if(dilateAmt < 1) dilateAmt = 1;
println(dilateAmt);
}
Note that the end result is raster, not vector.
If you want to achieve the exact effect you will need to port your example from JavaScript to Java. The source code is available.
If you like Processing the above example you could use plain javascript using p5.js. You'll find most of the familiar functions from Processing, but also directly use the paper.js library.
I am trying to draw a 10 millisecond grid in a QGraphicsScene in Qt. I am not very familiar with Qt... it's the first time I used it, and only because the application needs to be portable between Windows and Linux.
I actually don't have a problem drawing the grid, it's just the performance when the grid gets big. The grid has to be able to change size to fit the SceneRect if/when new data is loaded into the program to be displayed.
This is how I do it at the moment, I hate this but it's the only way I can think of doing it...
void Plotter::drawGrid() {
unsigned int i;
QGraphicsLineItem *line;
QGraphicsTextItem *text;
char num[11];
QString label;
unsigned int width = scene->sceneRect().width();
unsigned int height = scene->sceneRect().height();
removeGrid();
for (i = 150; i < width; i+= 10) {
line = new QGraphicsLineItem(i, 0, i, scene->sceneRect().height(), 0, scene);
line->setPen(QPen(QColor(0xdd,0xdd,0xdd)));
line->setZValue(0);
_itoa_s(i - 150, num, 10);
label = num;
label += " ms";
text = new QGraphicsTextItem(label, 0, scene);
text->setDefaultTextColor(Qt::white);
text->setX(i);
text->setY(height - 10);
text->setZValue(2);
text->setScale(0.2);
//pointers to items stored in list for removal later.
gridList.append(line);
gridList.append(text);
}
for (i = 0; i < height; i+= 10) {
line = new QGraphicsLineItem(150, i, width, i, 0, scene);
line->setPen(QPen(QColor(0xdd,0xdd,0xdd)));
line->setZValue(0);
gridList.append(line);
}
}
When scene->sceneRect().width() gets too big, however, the application becomes very sluggish. I have tried using a QGLWidget, but the improvements in speed are marginal at best.
I ended up using a 10x10 square pixmap and drew it as the backgroundBrush on my QGraphicsView, as is suggested in the link in the comment under my initial question.