IcoskaiPentagon Art Project

by shipmodeller1 in Craft > Art

466 Views, 1 Favorites, 0 Comments

IcoskaiPentagon Art Project

A66A9735a.jpg

There is a local art show called "Something Red" that I enter on occasion here. The show's primary theme is to create something that highlights the color red, given the time of the year. I also do a lot, and I mean a LOT, of java coding, so I thought that I could marry both and produce my art. And I wanted it to be unique, and possibly self generating. The project would be created on either my laser or cnc machines.

Supplies

I had a good supply of wood to use, so I selected some Purpleheart, Bloodwood, River Birch, Maple and Wenge to be my main carriers , along with thin dyed red, yellow and black to be used as my inlays. I also needed a specialized canvas to hold my amulets, so I purchased some canvas from a local craft store, and I intended to reuse some Oak wood I had laying around for the frame. The amulets would be attached to the canvas by yellow wood glue.

Creating the Idea

I created a program about three years ago that allowed me to create various shapes for use with my box making work. It was modular enough, so adding functionality just required me to write a new "tab" of code to load into the program. So I started out thinking that the project could produce rings of objects around a center object.. Pretty simple I thought, no so simple to implement. My focus was heads down writing what I thought would take me a day to complete.

Four Days Later

design1.png

Yeah, one day passed, two days, three days.. and finally, on the fourth day, I had something I could use. I discovered that I was too slow to manually try all the permutations to see how it looked. So I put buttons, spinners and number fields to control what I thought were the important aspects of what I wanted to get done. So, I can control the Initial size of the center image, and the number of rings to build. I could use circles or squares, though I opted for circles for this project. Future adaptations might add polygons. I chose to add a randomized button to change the size of the circles, and I also added functionality to change the minimum and maximum size of the circles. After a few iterations of the update button, I think I achieved what I was looking for.

The Code

It took a lot of code to get the fits right. The program calculates the number of objects that can fit on each ring, and then adjusts the sizes so that they just about touch each other. I had programmed in a boundary size, so we can control exactly how much room we do have. After each run, besides the visual display, I get a summary of the rings:

Ring: 1 Sine: 0.564497885257563 Degrees: 360.0 Steps: 5 Angle: 72.0 Direction: false
    Adjacent: 63.26704818276728  Opposite: 36.26704818276728 Total Arc: 360.0
Ring: 2 Sine: 0.32189647558115386 Degrees: 360.0 Steps: 9 Angle: 40.0 Direction: false
    Adjacent: 161.41349421935212  Opposite: 54.879397853817544 Total Arc: 360.0
Conflict: 15 Ring: 3
Ring: 3 Sine: 0.20572390785582753 Degrees: 360.0 Steps: 15 Angle: 24.0 Direction: false
    Adjacent: 273.8649137264769  Opposite: 56.572021653307246 Total Arc: 360.0
Ring: 4 Sine: 0.024166017683055083 Degrees: 359.9999999999993 Steps: 129 Angle: 2.7906976744186047 Direction: false
    Adjacent: 339.6472546912791  Opposite: 8.21031931149497 Total Arc: 360.0
Ring: 5 Sine: 0.1164363188456519 Degrees: 360.00000000000006 Steps: 26 Angle: 13.846153846153847 Direction: false
    Adjacent: 394.0539907835076  Opposite: 46.196416780733514 Total Arc: 360.0
Ring: 6 Sine: 0.12549315446599302 Degrees: 360.0 Steps: 24 Angle: 15.0 Direction: false
    Adjacent: 504.0033818800391  Opposite: 63.75297431579805 Total Arc: 360.0
Ring: 7 Sine: 0.11676699500588567 Degrees: 360.00000000000006 Steps: 26 Angle: 13.846153846153847 Direction: false
    Adjacent: 643.4019322967755  Opposite: 75.6455761009383 Total Arc: 360.0

This run ended up to be a 26 sided one (check ring 7 ) , the one I chose to build was a 25 sided one. All the angles and position factors was done with sine cosine, with trig used for distance and separation. A partial copy of the code I built for that portion is as follows:

 // Repeat the circles here for the number of rings selected
    for (int i = 0; i < rings; i++) {
      if (reverseCheckbox.isSelected()) {
        direction = !direction;
      }
      // Check if want random sizes
      if (this.randomSizeCheckbox.isSelected()) {
        double randomNumber = Math.random();
        double minRandom = Double.valueOf(this.minRandomSize.getText());
        double maxRandom = Double.valueOf(this.maxRandomSize.getText());
        secondRadius = randomNumber * (maxRandom - minRandom);

      } else {
        secondRadius = startRadius + increments;
      }
      // This now moves the X axis to where we want to put the circles
      initialLength += secondRadius;

      // Now let's see how long the actual side is
      double adjacentSide = initialLength;
      double compensation = adjustment * (i + 1);

      adjacentSide += compensation; // * we increased the leg.. but we should add this onto the points

      double adjustedRadius = secondRadius += adjustment;

      // calculate the sign SOH Opposite / hypontenuse
      double sine = secondRadius / Math.sqrt((adjacentSide * adjacentSide) + (adjustedRadius * adjustedRadius));
      double result = 2 * Math.toDegrees(Math.asin(sine));

      double degrees = 0.0;
      int steps = (int) (360 / result);
      double steppers = 360.0 / steps;

      // Create a list for the circles we create
      LinkedList<QuantumShapeInterface> circles = new LinkedList();
      LinkedList<Object> svgPath = new LinkedList();

      Double originalSecondRadius = secondRadius;

      // Do the circle of circles here
      while (degrees + steppers < 361.0) {
        double radians = Math.toRadians(degrees);
        double newX = Math.sin(radians) * adjacentSide;
        double newY = Math.cos(radians) * adjacentSide;
        //circle = new QuantumCircle(newX + baseStartX, newY + baseStartY, secondRadius);
        double modifier = .75;
        if (this.radioCircles.isSelected()) {
          circle = new QuantumCircle(newX + baseStartX, newY + baseStartY, secondRadius);
        } else {
          circle = new QuantumSquare(newX + baseStartX, newY + baseStartY, secondRadius);
          modifier = .6;
        }

     Now that we had the rings done, we needed to jazz this up.

design2.png

I spent another day doing some quick coding to allow me to add images to each medallion. SVG images are something I never worked with before, so of course, I buckled down to do some imports of that format. I knew this could get carried away, so I only did a minimal port to get the basics done. I added a few buttons to load images, scales them, and only place an image if the medallions were of a certain minimal size. Partial code for this area:

if (svgReader != null) {
          if (minSize <= secondRadius) {
            double dieg = direction ? 90 : 270;
            svgReader.computeScale((secondRadius * 2.0) * modifier);
            svgReader.setRotation(dieg - degrees);
            svgReader.setTranslationX(newX + baseStartX, newY + baseStartY);
            svgReader.parseSvg();
            svgReader.moveObjects(svgPath);
          }
        }
        circle.setRotation(degrees);
        if (degrees == 0.0) {
          circle.setStrokeColor(Color.CYAN);
        } else {
          circle.setStrokeColor(Color.BLUE);
        }
        circles.add(circle);
        if (degrees > 0.0) {
          if (!circle.valid((QuantumShapeInterface) circles.getFirst())) {
            degrees = 0;
            circles = new LinkedList();
            svgPath = new LinkedList();
            secondRadius--;
            System.out.println("Conflict: " + steps + " Ring: " + (i + 1));
            continue;
          }
        }

So I also decided to rotate the image as if it was going around the center point, to bring the title of this work to life.

Generating the Cuts

lb.png

The program I wrote generates the code to send to the actual program that will do the burns. In this case, LightBurn. When I sent it over, I saw right away that I would be having some issues. It was far too complicated to burn at once. I would have to isolate the layers, and then generate templates to help me place the amulets. Well, that part was fairly simple. I first had to scale the work so that it fit the criteria of being no bigger than 20" x 20". This was very easy to do in LightBurn.

Template Creation

templates.png
A66A9807a.jpg

I used LightBurn to drop all the butterflies, and separated each ring, in essence, this created the templates. I used cardboard then to burn each template. The completed templates are shown on my shop floor. Now, I can center each template, then put the medallions on the canvas with precision. But I still had to create the medallions. I would have to do a lot of manual manipulation in LightBurn to arrange all the medallions, and inlays, to be efficient on use of wood. Well, back to coding ....

Writing a Packing Algorithm

fit.png
packing.png

My source wood is not of stock sizes. I have bits and pieces, and I was trying to use the most wood with the least waste of the expensive materials. Now, packing algorithms are the source of many a college thesis, and few have successfully completed the actual work. But, mathematically, I chose to try with a few simple ideas. One, I will have a fixed size medallion or butterfly to cut. Two, I needed a bit of a separation between parts for the laser beam. So, I generated up another "tab" for my code, and added on fields to handle the size of my wood, the number of objects I need to burn, the size of the medallions for that ring, spacing. The code then generates best fit, and I transferred the results to LightBurn. I repeated this for all the rings. The code wasn't all that difficult. But very tedious. A small sample:

double multiplier = this.radioCircles.isSelected() ? 0.8 : 1.0;
    double adjustment = 0.0;
    for (int index = 0; index < pc.maxObjects; index++) {
      if (pc.targetX + pc.startRadius > bsX + pc.objectWidth - pc.edgeBuffer) {
        if (radioTight.isSelected() || whichPack) {
          direction = !direction;
        }
        if (direction && this.radioCircles.isSelected()) {
          pc.targetX = bsX + (2 * pc.startRadius) + pc.edgeBuffer;

        } else {
          pc.targetX = bsX + (1 * pc.startRadius) + pc.edgeBuffer;
        }
        pc.targetY += (2 * pc.startRadius) * multiplier;
      }
      if (pc.targetY + pc.startRadius >= (bsY + pc.objectHeight)) {
        break;
      }
      counts++;
      if (!whichPack) {
        if (this.radioCircles.isSelected()) {
          circle = new QuantumCircle(pc.targetX, pc.targetY, pc.startRadius - pc.buffer);
        } else {
          circle = new QuantumSquare(pc.targetX, pc.targetY, pc.startRadius - pc.buffer);
        }
        circle.setStrokeColor(Color.GREEN);
        this.getCanvasCallback().appendShape(circle);
      } else {
        // Put a rectangle around the object
        circle = new QuantumSquare(pc.targetX, pc.targetY, pc.startRadius);
        circle.setStrokeColor(Color.PURPLE);
        this.getCanvasCallback().appendShape(circle);
        adjustment = 2.0;
      }

      if (svgReader != null) {
        if (whichPack) {
          svgReader.setStrokeOverride(Color.BROWN);
        }
        if (minSize <= pc.startRadius) {
          if (pc.scale == 0.0) {
            svgReader.computeScale(((pc.startRadius - pc.buffer) * 2.0) * pc.imageScale);
            pc.scale = svgReader.getScale();
          }
          svgReader.setRotation(0);
          svgReader.setTranslationX(pc.targetX, pc.targetY);
          svgReader.parseSvg();
          svgReader.moveObjects(canvasCallback);
        }
      }
      pc.targetX += (2 * pc.startRadius) + adjustment;
    }
    return counts;

I could now burn and assemble all my medallions and associated inlays.

Assembly

A66A9717.JPG

Rather anticlimactic, but the hardest part of assembly was creating the canvas. I used the laser to cut out the icosikaipentagon, cut all the 25 Oak braces on my table saw. I only used an angle on one side of each piece. Makes it easier, and the fit would be better. I had the laser draw the lines for me where to lay the wood, so the assembly was fast. Let it dry overnight. The next morning, I sprayed the top with spray adhesive, and put the canvas on. I used a J roller to make sure there were no bubbles. I then trimmed the canvas and wrapped each of the 25 sides. After that was completed, the canvas was coated with white Gesso. Gesso turns the brown canvas a brilliant white, and gives a "tooth" that the glue can grab on to. I used the outer template to mount my center medallion, making that the "Master" pin that all my templates would register to. Using the rest of the templates, starting at the outer ring, I laid in all my medallions. A bit of cleaning up the back, adding the hanging wire .. and done.

Summary

I am quite pleased with how the project turned out, and already wrote some new "tabs" to handle Archimedes Spirals and Mouse Catching spirals. I do have plenty of videos that I may compile and post later.