Close
0%
0%

Does Anyone Really Know What Time It is?

If you havent noticed, the clock in the Windows Taskbar has gone missing. Will it ever return?

Similar projects worth following
532 views
0 followers
Perhaps members of the open-source community need to band together and create their own open-source Desktop Accessories. Just thinking out loud here, but maybe not. For now, the expanded Windows clock with an actual second hand is missing. So how hard can it be to write an even better one from scratch? Let's get busy!

About a year or so ago, or whenever it was, I decided to ask Microsoft Co-Pilot to help me write a C++ function that would calculate the angle bisectors of an arbitrary triangle, that is, without using conditional expressions or branches.  The response that I got was, of course, completely wrong, so I put myself to the task of actually trying to write something that works, correctly, especially since if I was writing a game engine, and if I needed to compute the angle bisectors of millions of triangles, let's say CUDA style, well we all know what happens when one thread in a group of threads running concurrently causes a pipe-line stall.  That's right - all other threads in the group will stall together.  What a MESS!  Unnecessary branches also increase the risk of Meltdown and/or Spectre-type attacks on vulnerable systems.  So how much worse can it get?  

Well, in any case - I put myself to the task of writing a solution that works, that is to say - according to my own self-imposed requirements, and for the part of actually doing that part of tessellation correctly, it isn't all that hard.

int triangle::generate_bisectors ()
{
    fpoint U1,U2,U3;
    MATH_TYPE d; 
    MATH_TYPE dx1,dx2,dx3,dy1,dy2,dy3;
    MATH_TYPE L1,L2,L3;
    MATH_TYPE c1,c2,c3,s1,s2,s3;

    // first find the sines and cosines of the line
    // segments that make up the triangle

    dx1 = current[1].x-current[0].x; dx2 = current[1].x-current[2].x;
    dx3 = current[2].x-current[0].x; dy1 = current[1].y-current[0].y;
    dy2 = current[1].y-current[2].y; dy3 = current[2].y-current[0].y;

    L1 = sqrt((dx1*dx1)+(dy1*dy1));
    L2 = sqrt((dx2*dx2)+(dy2*dy2));
    L3 = sqrt((dx3*dx3)+(dy3*dy3));

    c1 = dx1*(1.0/L1); c2 = dx2*(1.0/L2); c3 = dx3*(1.0/L3);
    s1 = dy1*(1.0/L1); s2 = dy2*(1.0/L2); s3 = dy3*(1.0/L3);

    // now generate three points that represent the
    // directional unit vectors for each line segment
    // and then  generate the compass points

    fpoint C1,C2,C3,C4,C5,C6;
    d = 1.0; // compass distance!
    U1.x = d*c1; U1.y = d*s1;
    U2.x = d*c2; U2.y = d*s2;
    U3.x = d*c3; U3.y = d*s3;

    C1 = current[0]+U1; C4 = current[0]+U3;
    C2 = current[1]-U2; C5 = current[1]-U1;
    C3 = current[2]-U3; C6 = current[2]+U2;

    // the directional unit vectors can be used to find the midpint
    // of a line that besects an isosceles triangle that forms
    // from the base of the "arrow"
    
    fpoint P0,P1,P2;
    P0 = fpoint::midpoint (C1,C4);
    P1 = fpoint::midpoint (C2,C5);
    P2 = fpoint::midpoint (C3,C6);

    fline AP1,BP2,CP3;
    AP1 = fline (current[0],P0);
    BP2 = fline (current[1],P1);
    CP3 = fline (current[2],P2);

    J = fpoint::intersect (AP1,BC);
    K = fpoint::intersect (BP2,AC);
    L = fpoint::intersect (CP3,AB);
    return 0;
}

O.K., so that is one way of doing it.  More work to be done, of course, checking the time, the time-zone, drawing the background image, drawing an hour hand, a minute hand, a second hand, etc.  Then maybe redo the whole thing so that the same code base can be used for analog aviation instruments.   Yet there is something very satisfying about knowing, going out the gate - that at least one really important detail, such as possibly having a very nice, even ornate pointer, is already done. Then again ... 

Then again, of course, this is an excellent opportunity to mention Euclid, with 100's of proofs waiting to be properly rendered, all with just the right amount of rigor, naturally!

Naturally, we are going to need to do more than have an elaborate method for drawing a nice ornate pointer; we are going to need the clock face, some numbers, and so on.  Yet, how are we going to do that?  By appealing to functions like sine and cosine?  Never!  Although the law of sines might have been known during the times of Pythagoras and Euclid, there was no way to calculate sines and cosines of arbitrary numbers until after the invention of calculus.  Yet there were other constructions that were well known, i.e., during the...

Read more »

  • Beyond the Sands of Time?

    glgorman05/06/2025 at 09:17 0 comments

    Perhaps my drawing room needs an old-fashioned drafting table, for my compass and straight-edge proofs. A clock on the wall would be nice, as would be some books for my bookshelves. The piano still needs legs and a place for some sheet music. Thus, while writing a game engine entirely from scratch is never an easy undertaking, I still think that it is a worthwhile endeavor. Most who dwell around these parts will understand why.

    So, yeah - I am having thoughts about making a game engine that contains some kind of object editor, "in-game", as it were, or as I should say, as it eventually will be.  Then I also want to have the stuff from "Teapot in the Garden", which you can find elsewhere, i.e., along the photo-realistic hair generating stuff, that also does blades of grass, trees, etc., all based on the same theory of "Digital DNA" based procedural mesh generation, among other things, and where some of other things includes the foundational stuff that is all based on the principles of Euclid, also as previously discussed.

    Thus, likewise, I think that AI, LLMs, and transformers as such are going to turn out to be quite useful, not just for giving personality to avatars, as such, but also for doing things according to some modern variant of SHRDLU, which I am also still working on, in addition to the Eliza stuff, believe it or not.

    Not that I couldn't perhaps run some variant of Ki-CAD as an ActiveX X control, for example, that is to say, within a view - inside a game engine perhaps? Even if the Meta-verse is pretty much a failure.  Even if Microsoft BOB was a failure.  Just so long as I don't try to reinvent "Clippy!"  Right?

    O.K., maybe an old-fashioned analog clock on one of those walls would be nice, at least for now.  Along with an old-fashioned drafting table.

    I wonder how many people remember that BeOS could do "books" with page-turning effects, along with animations on the individual pages?  A rather impressive feat for the late 90's, that is, that something like that could actually be done, even then without a GPU, i.e., on just a PowerPC.

    Then there is reflection, as an optical concept, or as a psychological concept, or even as a programming concept.  This is something to ponder - or at least reflect upon.

    To be continued ...

  • What if Time could go Sideways?

    glgorman05/02/2025 at 20:22 0 comments

    Well, time doesn't go sideways, but I can turn my 3-D perspective view of the Euclid style renderings on its side, just because it is possible to do.  Of course, there is the idea of Feynman's sum-over-all histories approach to quantum electrodynamics, where one interpretation might be to allow for time to act, perhaps like it has multiple dimensions, which converge, usually, to a single path chosen.  Yet, that is not what this post is about.   What then is this post about?  Well, keep reading.

    I saw the other day how someone got an LLM to run TinyStories260K on a C64 with 2MB of RAM expansion, of course, and that looks interesting, obviously - especially if LLAMA2 can be reduced to just 700 lines of C.  So, I think that I am on track as far as eventually doing a better AI based on some of my log entries from Hackaday, among other things.  Thus, this log entry, like many others, will eventually, all in due time of course, go into the training file for a small LLM, as it were, or else I should perhaps say, as it will be.  So that is part of the method for the madness.

    Other than that, I realized something while finally rendering the hexagon.  Something quite interesting, that is.  Here is a simple question.  Is it better to draw five hexagons, according to the vertices of the pentagon, and thereby obtain, hopefully, a set of 30 points that can be further used to construct the 60-minute marks, as well as the hour marks for a clock face?   Or is it better to construct one reference hexagon and then construct six pentagons, even though that would obviously be more work computationally?  The definition of "better," of course, might depend on such things as the accumulation of roundoff error, for example, and maybe compute time doesn't matter so much, if the calculations, all being done without trig calls of course, only need to be done once, as in the constructor for a master set of points when a module is instantiated.

    Then I realized that there might be a third approach.  Draw a simple equilateral triangle inside a circle.  Then construct at least one pentagon, sharing a vertex, and then, according to the points of the pentagon, construct a couple of hexagons, acting as if kind of random, in effect, just doing whatever, so as to get more points.

    This could get messy, since some sets of vertices might get constructed more than once, and maybe some comparisons and sorting operations would need to be performed, even though that would probably involve branches, and it would also really mess with things as far as the meanings of words like "proof" and "rigor" are concerned, especially insofar as trying to prove the equivalence of the results of an analytic construction vs. a real world compass and straight edge construction are concerned.

    Fortunately, I don't think that would involve an infinite regression, just some kind of tree search that could include redundancy checking, as a part of a larger equivalence testing regimen.

  • As Time Goes By

    glgorman04/19/2025 at 13:53 0 comments

    Alright, I got the code for drawing a decagon working by using the points of a pentagon to get things started,

    There are at least three ways that I can think of for doing this.  One would of course be to compute the angle bisectors of the internal triangles, which would be computationally expensive, but it would also be useful to take a look at some law of cosines computed values for the various internal angles, just as a test to see how much round-off error is being accumulated.  All without making use of trig calls, of course!  Then there is the method of simply finding the midpoint of each edge and plotting additional vertices by extending a line from the center of the pentagon to the point where it would intersect a circle.  A third method might be to simply reflect the set of vertices of the pentagon by any suitable axis of asymmetry.

    Otherwise, I haven't decided just how far I want to go with the branchless programming meme, but it does appear to have a lot of life left in it, if I decide to push things further.  Another potentially useful variation would be to use so-called "trampolines" to help in the translation, let's say, of some kind of Eliza-style command parser that takes English text in the form of statements like "Determine the bisectors of angle ABC, and plot the points as D, E, and F.  Thus, lookup tables for words like "bisectors" might be used to map English text onto the addresses of callable functions.  Maybe then a simple AI could more or less "read" Euclid's elements directly, and create the appropriate drawings without needing to write additional code?

    This would save a considerable amount of time.

  • Once upon a Time: According to Euclid?

    glgorman04/09/2025 at 23:21 0 comments

    O.K. So, for whatever it's worth.  I managed to get the pentagon drawing code working - that is to say, without having to make any calls to any trig functions in the actual pentagon drawing code.

    Yeah, it's pretty wild.  Based on the fact that the cosine of 36 degrees is equal to (1+sqrt(5))/4, I decided to perform the construction as if using a compass and straight edge, so that I could calculate the diagonal of a suitable rectangle (1.0 wide by 0.5 high), and then add the value of the height of the rectangle, to obtain a (1+sqrt(5))/2 line segment. from which I can construct a suitable bisector/midpoint value, which then gets used as the needed cosine part.  Additional work, Euclidian style, gets all of the points of a pentagon, such as by constructing a 36-degree angle, then bisecting THAT to obtain an 18-degree angle - to which 90 degrees can be added by making use of its perpendicular!  Various reflections and intersections later, all that is needed to be done has been done - and the pentagon can be plotted.  With no conditional statements needed either, other than in some code that is used to decide how much debugging information to print out or plot.  Oh, what fun!

    Next, I need to consider the importance of drawing the hexagon and methods for combining the techniques so as to perhaps plot five rotated hexagons according to the points of the pentagon, for example, which upon further bisections should give both the hour and minute marks of a clock face, without needing loops, branches, or trigonometric functions, perhaps?  Well, maybe.

    All in due time.

  • Time For a Log Entry

    glgorman04/02/2025 at 17:07 0 comments

    So, I have been thinking about the problem of drawing a clock face, that is, without making use of trig calls or precomputed tables, and a whole bunch of stuff comes to mind, like in the project description where I mention the fact that it is possible to construct a regular pentagon with compass and straightedge methods alone.  Yet, it is quite surprising how much actual work is involved in implementing something as simple as bisecting an arbitrary angle.  Even though, of course, once the heavy lifting is worked out in a manner worthy of Euclid, it becomes possible to have that particular tool available, with nothing more than a function call.  So, let's turn our attention, therefore, to the more general problem of drawing circles, and then to the various figures that can be inscribed therein.

    You would think that adding a function call, something like draw_circle would do the trick.  But NO, there is, in fact, as far as I know, no actual draw circle function in Windows GDI.  Never has been.  Not now, and not all the way back to Windows 1.0 either.  There is a draw ellipse function that we could use if we wanted to just use GDI, but of course, I don't want to do that.  What if I wanted a simple 2D clock, or if I wanted to draw a clock face on a 3D clock tower, where the 3D hands might cast a shadow on the face of the clock, depending, of course, on the longitude and latitude, the local weather, and so on?

    So, we need to be able to work with ordinary Euclidian constructions on the one hand while also being able to contemplate doing things with our planar object, like warping things onto the surface of cylinders, spheres, and so on.  Or just viewing things in 3-D, even though they might be 2-D.  Well, in any case, let's look at one way to draw a circle in 2-D and then fix it later so we can have some of the other, more fun stuff.

    ////////////////////////////////////////////////////////////////////
    // 
    //    PROPOSITION ???
    //
    //    Given a point on the plane representing the center of a circle
    //    and a point on the plane representing a point on the
    //    circumference of a circle, plot the indicated circle.
    //
    //    THE ELEMENTS OF EUCLID - Translated by John Casey
    //    Pubished 1887 by Cambridge Press, public domain.
    //
    ////////////////////////////////////////////////////////////////////
    
    void euclid::draw_circle (const fpoint &p1, const fpoint &p2)
    {
        SETCOLOR _(m_pdc,COLOR::yellow,NULL);
    
        MATH_TYPE x1,y1,x2,y2;
        MATH_TYPE dx, dy, r, r2;
        MATH_TYPE x_scale, y_scale;
        CRect rect;
    
        x_scale = x_dpi*m_scale;
        y_scale = y_dpi*m_scale;
        MATH_TYPE height;
        height = bounds.Height();
        
        // find radius of circle
        dx = (p1.x-p2.x);
        dy = (p1.y-p2.y);
        r = sqrt (dx*dx+dy*dy);
        x1 = (p1.x-page.x_offset)*x_scale;
        y1 = height-(p1.y-page.y_offset)*y_scale;
        r2 = r*x_scale;
    
        rect.bottom = y1+r2;
        rect.top = y1-r2;
        rect.right = x1+r2;
        rect.left = x1-r2;
        
    //    Todo - use a custom drawing method here
    //    instead of Windoze - especially when we
    //    get to the point where we are going to
    //    be drawing the shadow of a cone, for example
    //    on another plane - in 3d of course!
        
        write (output,"euclid::draw_circle p1.x = ",p1.x,", p1.y = ",p1.y);
        write (output,", p2.x = ",p2.x,", p2.y = ",p2.y);
        writeln (output,", computed radius = ",r);
    
        m_pdc->Ellipse...
    Read more »

View all 5 project logs

Enjoy this project?

Share

Discussions

Gravis wrote 03/30/2025 at 21:28 point

Stop being a Microsoft slave. Seriously, Linux is just one other OS that has a full desktop. I'm using it right now and the clock/calandar widget is great. You can fully customize how the time is displayed. Your desire to continue to be abused by Microsoft is mystifying.

  Are you sure? yes | no

Similar Projects

Does this project spark your interest?

Become a member to follow this project and never miss any updates