Jump to content

Revisiting an old hobby


AndyHull

Recommended Posts

Posted (edited)

I feel I should call this post "Artificial Intelligence creates a watch dial."

I present possibly the worlds first AI generated python code to produce an SVG graphic for a 30mm watch dial.

First... I went to ChatGPT and asked it the following question.
 

Quote


Can you write a python script to generate svg code to draw a white circular watch dial with a diameter of 30mm and dark blue minutes and hour markers. Add a 3mm solid black circle in the center of the dial

It responded with the following code...

 

def generate_svg_watch_dial_with_markers(diameter, num_minutes_markers, num_hours_markers, hole_radius):
    svg_content = f'<svg width="{diameter}mm" height="{diameter}mm" xmlns="http://www.w3.org/2000/svg">\n'

    # Draw white circle for watch dial
    svg_content += f'<circle cx="{diameter/2}mm" cy="{diameter/2}mm" r="{diameter/2}mm" fill="white" stroke="black" stroke-width="1"/>\n'

    # Draw markers for minutes
    for i in range(num_minutes_markers):
        angle = i * (360 / num_minutes_markers)
        x1 = diameter / 2 + (diameter / 2 - 2) * math.cos(math.radians(angle))
        y1 = diameter / 2 + (diameter / 2 - 2) * math.sin(math.radians(angle))
        x2 = diameter / 2 + (diameter / 2 - 6) * math.cos(math.radians(angle))
        y2 = diameter / 2 + (diameter / 2 - 6) * math.sin(math.radians(angle))
        svg_content += f'<line x1="{x1}mm" y1="{y1}mm" x2="{x2}mm" y2="{y2}mm" style="stroke:darkblue;stroke-width:1"/>\n'

    # Draw markers for hours
    for i in range(num_hours_markers):
        angle = i * (360 / num_hours_markers)
        x1 = diameter / 2 + (diameter / 2 - 2) * math.cos(math.radians(angle))
        y1 = diameter / 2 + (diameter / 2 - 2) * math.sin(math.radians(angle))
        x2 = diameter / 2 + (diameter / 2 - 8) * math.cos(math.radians(angle))
        y2 = diameter / 2 + (diameter / 2 - 8) * math.sin(math.radians(angle))
        svg_content += f'<line x1="{x1}mm" y1="{y1}mm" x2="{x2}mm" y2="{y2}mm" style="stroke:darkblue;stroke-width:2"/>\n'

    # Draw solid black circle in the center
    svg_content += f'<circle cx="{diameter/2}mm" cy="{diameter/2}mm" r="{hole_radius}mm" fill="black"/>\n'

    svg_content += '</svg>'
    return svg_content

import math

# Diameter of watch dial in mm
DIAMETER_MM = 30

# Number of minute and hour markers
NUM_MINUTES_MARKERS = 60
NUM_HOURS_MARKERS = 12

# Radius of hole in the center in mm
HOLE_RADIUS_MM = 1.5

svg_code = generate_svg_watch_dial_with_markers(DIAMETER_MM, NUM_MINUTES_MARKERS, NUM_HOURS_MARKERS, HOLE_RADIUS_MM)
print(svg_code)

I saved this as 30mmWatchDial.py
Next a ran the code (using python of course).

 python 30mmWatchDial.py >30mmWatchDial.svg

 ... and here is the result displayed in Inkscape.

image.thumb.png.497387ad2106e6292d304729c5e637ee.png

Here is a png of the .svg

 

30mmWatchDial.png.8b6c7c6a839243a911111dc75e3bbd09.png


.. and the .svg saved as a .svg.rtf is attached to the bottom of this post. 

Save it as .svg and you can open it in Inkscape.

Some things to bear in mind when playing with this idea.

The free version of ChatGPT can only write short snippets of code, so don't try to get too fancy or you will get incomplete results.

Image generating AI will produce arguably more interesting watch dials, like the one below, but they wont be in SVG format.

image.png.9bb2755cb25e56f6d3538b4bcaff9ac2.png


ChatGPT is available here -> https://chat.openai.com/

DeepAI image generator is here -> https://deepai.org/machine-learning-model/text2img

Have fun.

30mmWatchDial.svg.rtf

Just for fun, here is another AI generated watch. Spooky stuff.

cmqgdk2X.jpeg

Edited by AndyHull
  • Like 3
Link to comment
Share on other sites

Posted (edited)

I've just spent the last hour or so playing with this idea.


I had a play with ChatGPT a few months back and was reasonably impressed with its code writing abilities but I didn't pursue it as it was limited in its output.

The idea of creating a watch dial is by comparison,  pretty simple in its scope, so I actually started to get it to debug its own code.


If you have never seen ChatGPT in action you might like to read this thread.

https://chat.openai.com/share/d59f87c6-86aa-4a44-85eb-c801da463bf3

If you follow along you can see that it has an almost uncanny ability to figure out where it messed up.

It stumbled a bit at times, and I did suggest quite a few of the "fixes" but it actually did end up with some working code.

watch_dial_bauhaus_jpeg.thumb.jpg.7459e9462d6eb7a02e95431a8f19c48e.jpg
Here is the revised python  .SVG dial generating script.

import svgwrite
import math

def generate_watch_dial():
    # Create SVG Drawing with width and height in millimeters
    drawing = svgwrite.Drawing('watch_dial.svg', size=('30mm', '30mm'), profile='full')

    # Define styles
    dial_style = "fill:none;stroke:#2C3E50;stroke-width:0.1mm"  # Dark blue color for outer circle
    hour_marker_style = {"stroke": "#1F618D", "stroke-width": "0.4mm"}  # Dark blue color for hour markers
    minute_marker_style = {"stroke": "#34495E", "stroke-width": "0.2mm"}  # Slightly lighter shade of blue for minute markers
    center_circle_style = "fill:none;stroke:#1F618D;stroke-width:0.1mm"  # Dark blue color for center circle

    # Draw watch dial centered at (15mm, 15mm) with a radius of 15mm
    dial = drawing.circle(center=('15mm', '15mm'), r='15mm', style=dial_style)
    drawing.add(dial)

    # Draw center circle
    center_circle = drawing.circle(center=('15mm', '15mm'), r='1.5mm', style=center_circle_style)
    drawing.add(center_circle)

    # Define center coordinates in millimeters
    center_x, center_y = 15, 15

    # Define radius for markers in millimeters
    marker_radius = 12

    # Draw minute markers
    for minute in range(0, 60):
        minute_angle = math.radians(90 - minute * 6)  # Convert minute to radians
        minute_x_outer = center_x + marker_radius * math.cos(minute_angle)
        minute_y_outer = center_y - marker_radius * math.sin(minute_angle)
        minute_x_inner = center_x + (marker_radius - 1) * math.cos(minute_angle)  # Adjusted inner point
        minute_y_inner = center_y - (marker_radius - 1) * math.sin(minute_angle)  # Adjusted inner point
        marker = drawing.line(start=(f'{minute_x_outer}mm', f'{minute_y_outer}mm'),
                              end=(f'{minute_x_inner}mm', f'{minute_y_inner}mm'),
                              **minute_marker_style, stroke_linecap='round')
        drawing.add(marker)

    # Draw hour markers
    for hour in range(0, 12):
        hour_angle = math.radians(90 - hour * 30)  # Convert hour to radians
        hour_x_outer = center_x + marker_radius * math.cos(hour_angle)
        hour_y_outer = center_y - marker_radius * math.sin(hour_angle)
        hour_x_inner = center_x + (marker_radius - 2) * math.cos(hour_angle)  # Adjusted inner point
        hour_y_inner = center_y - (marker_radius - 2) * math.sin(hour_angle)  # Adjusted inner point
        marker = drawing.line(start=(f'{hour_x_outer}mm', f'{hour_y_outer}mm'),
                              end=(f'{hour_x_inner}mm', f'{hour_y_inner}mm'),
                              **hour_marker_style, stroke_linecap='round')
        drawing.add(marker)

    # Save SVG
    drawing.save()


if __name__ == "__main__":
    generate_watch_dial()

I'm not going to teach anybody how to install and run python, that is a little bit out of the remit of this thread, but if you have the skills and follow along with the chat, you can see it actually does some pretty neat "thinking", if that is the correct word.

image.thumb.png.b77747b825c502ec930919fdaaa36628.png

Here is our finished "Bauhaus" dial.

Could you print this on transfer paper? Absolutely, and it would be extremely accurate. 

Could you use this to drive a laser engraver? Yes, so long as the laser engraver can work with .svg files, although you could convert to any number of other formats, scaleable or raster, so in short, yes, it will work with a laser engraver, or with a vinyl cutter or whatever. Anything that has the resolution to produce fine detail would work. 

Finally, could I have written and debugged a similar script in less time without ChatGPT?

Possibly not on my own, but with a second human "buddy coding", and spotting errors and incorrect assumptions, maybe. I've worked with a lot of very sharp coders over the years and when the pressure is on, things can get done pretty quickly.

As you can see from the chatlog, ChatGPT did need quite a few hints, but then again, its not powered by coffee and pizza so what do you expect? It is however blisteringly fast at re-factoring its own code.

Feel free to use the code or the resultant svg and jpeg files if you want.
Consider them open source GPL licensed. Attributions to Mr ChatGPT and yours truly of course.

EDIT: If there is sufficient interest in expanding this idea, I may create a separate thread for it.  Any takers?

EDIT2: I posted the above code in a git repo here -> https://github.com/pingumacpenguin/ChatGPT-WatchDialCoding

Anyone can check out the code, and if you want to contribute changes or other versions, let me know, and I can set you up as a contributor.

Edited by AndyHull
Link to comment
Share on other sites

Posted (edited)

How about a numerical dial?

 

image.thumb.png.c7e56a3d95042bd4994725f32c61430d.png

 

.. and the ChatGPT python code...

import svgwrite
import math

def generate_watch_dial():
    # Create SVG Drawing
    drawing = svgwrite.Drawing('watch_dial.svg', size=(30, 30), profile='full')

    # Define styles
    dial_style = "stroke:#192A56;stroke-width:0.1mm;fill:none;"
    hour_marker_style = {"stroke": "#001F3F", "stroke-width": "0.2mm", "stroke-linecap": "round"}
    minute_marker_style = {"stroke": "#85C1E9", "stroke-width": "0.1mm", "stroke-linecap": "round"}
    center_circle_style = {"stroke": "#000000", "stroke-width": "0.1mm", "fill": "none"}
    hour_number_style = {"text-anchor": "middle", "dominant-baseline": "central", "font-size": "1mm", "fill": "#000000"}  # Black color for hour numbers

    # Draw watch dial
    drawing.add(svgwrite.shapes.Circle(center=(15, 15), r=15, style=dial_style))

    # Draw hour markers
    for hour in range(1, 13):
        if hour % 3 != 0:  # Skip drawing hour markers at 12, 3, 6, and 9
            angle = math.radians((hour - 3) * 30)  # Calculate angle
            x1 = 15 + 12 * math.cos(angle)  # Calculate x coordinate
            y1 = 15 + 12 * math.sin(angle)  # Calculate y coordinate
            x2 = 15 + 13 * math.cos(angle)  # Calculate x coordinate for line end
            y2 = 15 + 13 * math.sin(angle)  # Calculate y coordinate for line end
            drawing.add(drawing.line(start=(x1, y1), end=(x2, y2), **hour_marker_style))

    # Draw minute markers
    for minute in range(1, 61):
        if minute % 5 != 0:  # Skip drawing minute markers at 15, 30, 45, and 60
            angle = math.radians((minute - 15) * 6)  # Calculate angle
            x1 = 15 + 13.5 * math.cos(angle)  # Calculate x coordinate
            y1 = 15 + 13.5 * math.sin(angle)  # Calculate y coordinate
            x2 = 15 + 14 * math.cos(angle)  # Calculate x coordinate for line end
            y2 = 15 + 14 * math.sin(angle)  # Calculate y coordinate for line end
            drawing.add(drawing.line(start=(x1, y1), end=(x2, y2), **minute_marker_style))

    # Draw center circle
    drawing.add(svgwrite.shapes.Circle(center=(15, 15), r=1.5, **center_circle_style))

    # Draw hour numbers
    for hour, angle_offset in [(12, -90), (3, 0), (6, 90), (9, 180)]:
        angle = math.radians(angle_offset)  # Calculate angle
        radius = 11  # Radius of the circle passing through the midpoint of the hour marker lines
        x = 15 + radius * math.cos(angle)  # Calculate x coordinate
        y = 15 + radius * math.sin(angle)  # Calculate y coordinate
        drawing.add(svgwrite.text.Text(f'{hour}', insert=(x, y), **hour_number_style))

    # Save the SVG
    drawing.save()

generate_watch_dial()


.. and the chat that generated this ... -> https://chat.openai.com/share/d59f87c6-86aa-4a44-85eb-c801da463bf3

I added this to the git repo. You can clone the repo with git as follows
 

git clone https://github.com/pingumacpenguin/ChatGPT-WatchDialCoding.git

I let you figure out how to install git, python etc yourself.  Google is your friend.

Edited by AndyHull
Link to comment
Share on other sites

Posted (edited)
import svgwrite
import math

def generate_watch_dial():
    # Create SVG Drawing
    drawing = svgwrite.Drawing('watch_dial.svg', size=(30, 30), profile='full')

    # Define dial parameters
    center = (15, 15)
    radius = 12
    hour_marker_length = 1  # Length of hour markers
    minute_marker_length = 1  # Length of minute markers

    # Define styles
    background_style = {"stroke": "none", "fill": "#000000"}  # Black background
    marker_style = {"stroke": "#000000", "stroke-width": "0.2mm"}  # Black marker color

    # Draw background circle
    drawing.add(drawing.circle(center=center, r=radius, **background_style))

    # Draw hour markers
    for hour in range(1, 13):
        angle = math.radians((hour / 12) * 360 - 90)
        x1 = center[0] + math.cos(angle) * radius
        y1 = center[1] + math.sin(angle) * radius
        x2 = center[0] + math.cos(angle) * (radius + hour_marker_length)
        y2 = center[1] + math.sin(angle) * (radius + hour_marker_length)
        drawing.add(drawing.line(start=(x1, y1), end=(x2, y2), **marker_style))

    # Draw minute markers (only where there are no hour markers)
    for minute in range(1, 61):
        if minute % 5 != 0:  # Draw minute marker only if not at an hour position
            angle = math.radians((minute / 60) * 360 - 90)
            x1 = center[0] + math.cos(angle) * radius
            y1 = center[1] + math.sin(angle) * radius
            x2 = center[0] + math.cos(angle) * (radius + minute_marker_length)
            y2 = center[1] + math.sin(angle) * (radius + minute_marker_length)
            drawing.add(drawing.line(start=(x1, y1), end=(x2, y2), **marker_style))

    # Save the SVG file
    drawing.save()


if __name__ == "__main__":
    generate_watch_dial()

Here is python code to generate this black "bauhaus" dial with grey hour markers and lighter grey minute markers.

image.thumb.png.18bb27e725f94ef816865c2336304457.png

 

One thing that I've noticed is that ChatGPT struggles with the concept of placing text markers as it has difficulty with locating the centre of text objects and/or their bounding boxes. I think this is actually a limitation caused by the python svg library as it appears to lack the necessary object properties/functions to return these dimensions.

This makes placing text markers a more hands on process. "try the X11 (Roman numeral 12) marker a little further down and to the left" that sort of thing.

Since ChatGPT cannot "see" anything, the process of correcting its mistakes is entirely language based. I can't say something like  "can you not see that all of the hour markers are wrong? Sort them!" since it has no real concept of the visual results of its labours.

You can of course edit the resultant .svg file in Inkscape or whatever editor you use, and add your own text in whatever font and location you require.

I must admit this is actually quite a fun learning process, and ChatGPT has boundless patience, unlike some programmers I could name.


It doesn't like to bunk off for a coffee though which is a bit of a down side.

It also cannot see that the code it generated above has a bug, which actually improves the look of the markers. I didn't correct it.
 

As before, you can follow along with the creative process in the ChatGPT chat here -> https://chat.openai.com/share/d59f87c6-86aa-4a44-85eb-c801da463bf3

Also, if one of the @staff moderators can hive this section of this post in to a separate topic, that would make following it and finding it later much easier.

If this is not easy to do, I'll create a separate topic, and leave this lot here.
EDIT: I pushed the above "BauhausBlack.py" code to the git repo.

Edited by AndyHull
Link to comment
Share on other sites

Posted (edited)

In this case since the AI is neither checking that it code runs (sometimes it has bugs and throws errors), nor iterating the problem when it fails, and since it presumably would need to use some sort of pattern recognition to "see" the result of running the code, it cannot make decisions based on what it has created.

It does have the ability to work with the errors that the language throws back at it, and re-factor its code accordingly, but lacks the ability to run and re-run the code in the first place. 


However, both of those problems would be relatively easy to address if ChatGPT was purely a python generating image manipulating entity.

This dial creation problem a bit of an edge case for its use though, but yes, adding the ability to run its own code, and fix its own bugs in an iterative manner like a "real" coder, and to "see" images are both within the bounds of current technology.

It isn't about to make any "real" coders redundant any day soon though as although it is very good at what it does, the "I" in AI is still not truly there. It cannot make real world decisions and lacks the "imagination" necessary to provide the "problems" it is such a good tool for working with.

It does have an uncanny ability to re-factor its own "ideas" so if it trips over a particular issue and cannot fix a bug, it then tries a different approach to the problem as you will see from the chat log.

That log is worth a look, since you can see its abilities.

image.png.6c1f339eab41da4a93ecb71ae0e7ebd4.png

For example it produced a neat method for dealing with Roman numerals, but then struggles with the placement of them in a balanced layout on the dial as it couldn't figure out where they actually landed in the image without feedback from the human in the loop.

Edited by AndyHull
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.




×
×
  • Create New...