Skip to content

Commit 8a5b5a0

Browse files
committed
Clamp slider values to prevent intersections
1 parent 91dc656 commit 8a5b5a0

3 files changed

Lines changed: 53 additions & 30 deletions

File tree

deformedPenrose/2500.png

30 KB
Loading

deformedPenrose/empty.png

5.68 KB
Loading

deformedPenrose/main.p5.js

Lines changed: 53 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ let sketch = function(p) {
1818
const SLIDER_RESOLUTION = 30
1919
const SUBDIVISION_THRESHOLD = 7
2020

21-
let subdivisions = 7
21+
let subdivisions = 4
2222
let canvasSize
2323
let canvas
2424
let triangles = []
@@ -30,7 +30,7 @@ let sketch = function(p) {
3030
// Controls
3131
let shadeA, shadeB, shadeC, shadeAlabel, shadeBlabel, shadeClabel, subdivControl, shadeOffset, colourSelect
3232
let drawLines, debug, manualControl, recalcButton, deformButton, animateButton, exportCheck
33-
let doExport = true
33+
let doExport = false
3434
let phi1slider, phi2slider, phi4slider, phi5slider, phi6slider, phi7slider
3535
let p1, p2, p4, p5, p6, p7
3636
let palettes = [
@@ -43,7 +43,7 @@ let sketch = function(p) {
4343
{ "name": "Grey", "palette": { "a": "#141414", "b": "#444444", "lines": "#0a0a0a" } },
4444
{ "name": "Officer", "palette": { "a": "#EC994B", "b": "#15133C", "lines": "#15133C" } },
4545
]
46-
let palette = palettes[0]
46+
let palette = palettes[3]
4747

4848
// Create an ID based on the coordinates of the point - same coordinates will give consistent ID
4949
// Used to prevent duplicate points in node Map and destination Set
@@ -271,8 +271,8 @@ let sketch = function(p) {
271271

272272
// For 5 we have to resort to measuring angles between nodeOrigin and the destination nodes
273273
// angleNode is the node shared between the two blue triangles with the greatest angle (ie. fat side)
274-
// If we go around the destinations CW or CCW , measuring the angles, we will have a small angle (0.63),
275-
// then a big one (1.89). The destination corresponding to the first big one after a small one is the angleNode.
274+
// If we go around the destinations CW or CCW , measuring the angles, we will have a small angle (pi/5 ~= 0.63),
275+
// then a big one (3pi/5 ~= 1.89). The destination corresponding to the first big one after a small one is the angleNode.
276276

277277
// Sort destinations by angle
278278
sortedDests = [...node.destinations.values()].sort((a,b) => (a.sub(node.nodeOrigin).arg() > b.sub(node.nodeOrigin).arg() ? 1 : -1))
@@ -327,7 +327,7 @@ let sketch = function(p) {
327327
}
328328

329329
// nodes at the edge of the image can't be computed
330-
if(distHist.length == 16) {
330+
if(distHist.length == 18) {
331331
node.angle = 0
332332
break
333333
}
@@ -354,7 +354,7 @@ let sketch = function(p) {
354354

355355
function deformNode(node, phi) {
356356
node.phi = phi
357-
if(phi && node.angle) {
357+
if(node.angle) {
358358
let nodeTriangles = [...node.redTriangles, ...node.blueTriangles]
359359
// Perform deformation on all matching nodes
360360
nodeTriangles.forEach(triangle => {
@@ -585,18 +585,23 @@ let sketch = function(p) {
585585
phi4slider.value(p.random(0, SLIDER_RESOLUTION))
586586
phi5slider.value(p.random(0, SLIDER_RESOLUTION))
587587
phi6slider.value(p.random(0, SLIDER_RESOLUTION))
588-
phi7slider.value(p.random(0, SLIDER_RESOLUTION))
588+
// phi7slider.value(p.random(0, SLIDER_RESOLUTION))
589589

590590
// Randomise palette
591591
let selectedPalette = palettes[Math.floor(Math.random()*palettes.length)]
592592
palette = selectedPalette
593593
colourSelect.value(selectedPalette.name)
594594

595595
// Randomise subdivisions
596-
subdivControl.value(p.random(4, 8))
596+
subdivControl.value(p.random(3, 5))
597597
recalc()
598598
}
599599

600+
function exportAnimation() {
601+
t = 0
602+
doExport = true
603+
}
604+
600605
function toggleManual() {
601606
let enabled = manualControl.checked()
602607
if(enabled) {
@@ -642,7 +647,7 @@ let sketch = function(p) {
642647
}
643648

644649
p.preload = function() {
645-
inputImage = p.loadImage("ring.png")
650+
inputImage = p.loadImage("empty.png")
646651
}
647652

648653
p.setup = function() {
@@ -697,7 +702,7 @@ let sketch = function(p) {
697702
animateButton.mousePressed(animateOrStop)
698703

699704
exportCheck = p.createCheckbox("Export animation", false)
700-
exportCheck.changed(p.draw)
705+
exportCheck.changed(exportAnimation)
701706
exportCheck.position(canvasSize + 110, y)
702707

703708
exportButton = p.createButton("Export")
@@ -723,6 +728,7 @@ let sketch = function(p) {
723728
imageLabel.position(canvasSize + 20, y+=50)
724729
let sel = p.createSelect()
725730
sel.position(canvasSize + 20, y+=20)
731+
sel.option("empty.png")
726732
sel.option("ring.png")
727733
sel.option("dgen.png")
728734
sel.option("lineargrad.png")
@@ -761,19 +767,36 @@ let sketch = function(p) {
761767

762768
if(manualControl.checked()) {
763769
p1 = p.map(phi1slider.value(), 0, SLIDER_RESOLUTION, -short, short)
764-
p2 = p.map(phi2slider.value(), 0, SLIDER_RESOLUTION, -short*0.6, short)
765-
p4 = p.map(phi4slider.value(), 0, SLIDER_RESOLUTION, -short*0.6, short)
766-
p5 = p.map(phi5slider.value(), 0, SLIDER_RESOLUTION, -short*0.6, short)
767-
p6 = p.map(phi6slider.value(), 0, SLIDER_RESOLUTION, -short, short*0.6)
768-
p7 = p.map(phi7slider.value(), 0, SLIDER_RESOLUTION, -short*0.6, short*0.6)
769-
770+
p2 = p.map(phi2slider.value(), 0, SLIDER_RESOLUTION, -short, short)
771+
p4 = p.map(phi4slider.value(), 0, SLIDER_RESOLUTION, -short, short)
772+
p5 = p.map(phi5slider.value(), 0, SLIDER_RESOLUTION, -short, short)
773+
p6 = p.map(phi6slider.value(), 0, SLIDER_RESOLUTION, -short, short)
774+
p7 = p.map(phi7slider.value(), 0, SLIDER_RESOLUTION, -short, short)
775+
776+
// Clamp to avoid weirdness - this is a bit of a hack, but it gives a nice result
777+
// In case of a conflict, give p4 and p5 priority (ie. adjust the others to fit)
778+
p4 = Math.min(short*Math.sin(Math.PI/10)*2, p4)
779+
p5 = Math.min(short*Math.sin(Math.PI/10)*2, p5)
780+
p4 = Math.max(-short*Math.sin(Math.PI/10), p4) // This should be -short*2sin(pi/10), but scaling ALL the way creates a fully dark image, which looks crap
781+
p6 = Math.min(short-p5, p6)
782+
783+
p1 = Math.max(-short-p7, p1)
784+
p1 = Math.max((-0.9*short*Math.sin(Math.PI/10)*2-p4)/Math.sin(3*Math.PI/5), p1)
785+
p1 = Math.max(-short + 3*Math.sin(Math.PI/10)*Math.abs(p6), p1)
786+
787+
p2 = Math.max(-short*Math.sin(Math.PI/10)*2-p4, p2)
788+
p2 = Math.min((short-p4)/2, p2)
789+
790+
p7 = Math.min((short-p5)*0.5, p7)
791+
p7 = Math.max((-short+p5)*0.5, p7)
792+
770793
manualDeform(p1, p2, p4, p5, p6, p7)
771794
} else {
772795
deformTriangles(inputImage)
773796
}
774797

775798
p.background(palette.palette.lines)
776-
p.strokeWeight(drawLines.checked() ? 1 : 0)
799+
p.strokeWeight(drawLines.checked() ? 2 : 0)
777800
p.stroke(palette.palette.lines)
778801
for (let triangle of triangles) {
779802
if(triangle.type == 0) {
@@ -794,12 +817,12 @@ let sketch = function(p) {
794817

795818
if(manualControl.checked()) {
796819
let y = 35
797-
p.text("t1:" + p1.toFixed(2), canvasSize - 40, y+=30)
798-
p.text("t2:" + p2.toFixed(2), canvasSize - 40, y+=30)
799-
p.text("t4:" + p4.toFixed(2), canvasSize - 40, y+=30)
800-
p.text("t5:" + p5.toFixed(2), canvasSize - 40, y+=30)
801-
p.text("t6:" + p6.toFixed(2), canvasSize - 40, y+=30)
802-
p.text("t7:" + p7.toFixed(2), canvasSize - 40, y+=30)
820+
p.text("t1 " + p1.toFixed(3), canvasSize - 50, y+=30)
821+
p.text("t2 " + p2.toFixed(3), canvasSize - 50, y+=30)
822+
p.text("t4 " + p4.toFixed(3), canvasSize - 50, y+=30)
823+
p.text("t5 " + p5.toFixed(3), canvasSize - 50, y+=30)
824+
p.text("t6 " + p6.toFixed(3), canvasSize - 50, y+=30)
825+
p.text("t7 " + p7.toFixed(3), canvasSize - 50, y+=30)
803826
}
804827

805828
if(debug.checked()) {
@@ -818,13 +841,13 @@ let sketch = function(p) {
818841
p.vertex(canvasSize*(node.nodeOrigin.re + 1)/2, canvasSize*(node.nodeOrigin.im + 1)/2)
819842
p.vertex(canvasSize*(newVert.re + 1)/2, canvasSize*(newVert.im + 1)/2)
820843
p.endShape()
821-
822-
// Red dot at origin
823-
p.stroke("#f00")
824-
p.strokeWeight(5)
825-
p.point(canvasSize*(node.nodeOrigin.re + 1)/2, canvasSize*(node.nodeOrigin.im + 1)/2)
826-
p.strokeWeight(1)
827844
}
845+
846+
// Red dot at origin
847+
p.stroke("#f00")
848+
p.strokeWeight(5)
849+
p.point(canvasSize*(node.nodeOrigin.re + 1)/2, canvasSize*(node.nodeOrigin.im + 1)/2)
850+
p.strokeWeight(1)
828851

829852
// Label nodes which can be deformed
830853
if(node.type && node.type != 3) {

0 commit comments

Comments
 (0)