-
Notifications
You must be signed in to change notification settings - Fork 3
/
morphpoly.c
194 lines (147 loc) · 5.25 KB
/
morphpoly.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
/* morphpoly --- plot a morphed polygon 2016-11-03 */
/* Copyright (c) 2016 John Honniball, Froods Software Development */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <unistd.h>
#include <time.h>
#include "hpgllib.h"
/* Inspired by Manfred Mohr's "Lady Quark" of 1972, seen in */
/* figure 1.3 of "Generative Art" by Matt Pearson, ISBN 1935182625 */
// #define LADY_QUARK
struct Vertex {
double x;
double y;
};
int generate2polygons(const double radius, const double angle, const int nsides, const int nsubdiv, struct Vertex outer[], struct Vertex inner[]);
void splitside(const struct Vertex v1, const struct Vertex v2, const int nsubdiv, struct Vertex *result);
void morphpolygon(const double xc, const double yc, const int nsides, const struct Vertex inner[], const struct Vertex outer[], const int nsteps);
void drawpoly(const int nsides, const double xc, const double yc, const struct Vertex vertex[]);
int main(int argc, char * const argv[])
{
int opt;
int nsides;
double radius;
#ifdef LADY_QUARK
int x, y;
double xc, yc;
double w3, h3;
#else
double w4, h4;
#endif
double maxx, maxy;
struct Vertex inner[64], outer[64];
while ((opt = getopt(argc, argv, "no:p:s:t:v:")) != -1) {
switch (opt) {
case 's':
case 'n':
case 'o':
case 'p':
case 't':
case 'v':
plotopt(opt, optarg);
break;
default: /* '?' */
fprintf(stderr, "Usage: %s [-p pen] [-s <size>] [-t title]\n", argv[0]);
fprintf(stderr, " <size> ::= A1 | A2 | A3 | A4 | A5\n");
exit(EXIT_FAILURE);
}
}
srand((unsigned int)time(NULL));
if (plotbegin(1) < 0) {
fputs("Failed to initialise HPGL library\n", stderr);
exit(EXIT_FAILURE);
}
getplotsize(&maxx, &maxy);
#ifdef LADY_QUARK
radius = (maxy / 3.0) / sqrt(2.0);
w3 = maxx / 3.0;
h3 = maxy / 3.0;
for (y = 0; y < 3; y++) {
yc = (h3 / 2.0) + (h3 * y);
for (x = 0; x < 3; x++) {
xc = (h3 / 2.0) + (h3 * x) + ((maxx - maxy) / 2.0);
nsides = generate2polygons(radius, M_PI / 4.0, 4, 4, outer, inner);
morphpolygon(xc, yc, nsides, outer, inner, 20);
}
}
#else
radius = maxy / 4.0;
w4 = maxx / 4.0;
h4 = maxy / 4.0;
nsides = generate2polygons(radius, 0.0, 4, 4, outer, inner);
morphpolygon(w4 * 3.0, h4 * 3.0, nsides, outer, inner, 12);
nsides = generate2polygons(radius, 0.0, 5, 4, outer, inner);
morphpolygon(w4, h4 * 3.0, nsides, outer, inner, 12);
nsides = generate2polygons(radius, 0.0, 6, 4, outer, inner);
morphpolygon(w4 * 3.0, h4, nsides, outer, inner, 12);
nsides = generate2polygons(radius, 0.0, 7, 4, outer, inner);
morphpolygon(w4, h4, nsides, outer, inner, 12);
#endif
plotend();
return (0);
}
int generate2polygons(const double radius, const double angle, const int nsides,
const int nsubdiv, struct Vertex outer[],
struct Vertex inner[])
{
const double rad = radius * 0.2;
int i;
const double delta = (2.0 * M_PI) / (double)nsides;
struct Vertex vertex[64];
struct Vertex jiggle;
for (i = 0; i < nsides; i++) {
const double theta = (double)i * delta;
vertex[i].x = cos(theta + angle) * radius;
vertex[i].y = sin(theta + angle) * radius;
}
for (i = 0; i < nsides; i++) {
const int i1 = (i + 1) % nsides;
splitside(vertex[i1], vertex[i], nsubdiv, &outer[i * (nsubdiv + 1)]);
}
for (i = 0; i < (nsides * (nsubdiv + 1)); i++) {
jiggle.x = (((double)rand() / (double)RAND_MAX) * rad) - (rad / 2.0);
jiggle.y = (((double)rand() / (double)RAND_MAX) * rad) - (rad / 2.0);
inner[i].x = (outer[i].x / 3.0) + jiggle.x;
inner[i].y = (outer[i].y / 3.0) + jiggle.y;
}
return (nsides * (nsubdiv + 1));
}
void splitside(const struct Vertex v1, const struct Vertex v2, const int nsubdiv, struct Vertex *result)
{
int i;
for (i = 0; i <= nsubdiv; i++) {
const double p1 = i / (double)nsubdiv;
const double p2 = 1.0 - p1;
result[i].x = (v1.x * p1) + (v2.x * p2);
result[i].y = (v1.y * p1) + (v2.y * p2);
}
}
void morphpolygon(const double xc, const double yc, const int nsides, const struct Vertex outer[], const struct Vertex inner[], const int nsteps)
{
int i, j;
const double delta = 1.0 / nsteps;
struct Vertex vertex[64];
drawpoly(nsides, xc, yc, outer);
for (i = 1; i < nsteps; i++) {
const double innerportion = delta * i;
const double outerportion = delta * (nsteps - i);
for (j = 0; j < nsides; j++) {
vertex[j].x = (outer[j].x * outerportion) + (inner[j].x * innerportion);
vertex[j].y = (outer[j].y * outerportion) + (inner[j].y * innerportion);
}
drawpoly(nsides, xc, yc, vertex);
}
drawpoly(nsides, xc, yc, inner);
}
void drawpoly(const int nsides, const double xc, const double yc, const struct Vertex vertex[])
{
int i;
moveto(xc + vertex[0].x, yc + vertex[0].y);
for (i = 1; i < nsides; i++) {
lineto(xc + vertex[i].x, yc + vertex[i].y);
// circle(xc + vertex[i].x, yc + vertex[i].y, 20.0);
}
lineto(xc + vertex[0].x, yc + vertex[0].y);
}