Skip to content

Commit beeea06

Browse files
authored
Merge pull request #13 from frozar/koch-snowflake
Koch snowflake
2 parents c1d2581 + e35d9c5 commit beeea06

6 files changed

Lines changed: 370 additions & 0 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
.pio
2+
.vscode/.browse.c_cpp.db*
3+
.vscode/c_cpp_properties.json
4+
.vscode/launch.json
5+
.vscode/ipch
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
2+
This directory is intended for project header files.
3+
4+
A header file is a file containing C declarations and macro definitions
5+
to be shared between several project source files. You request the use of a
6+
header file in your project source file (C, C++, etc) located in `src` folder
7+
by including it, with the C preprocessing directive `#include'.
8+
9+
```src/main.c
10+
11+
#include "header.h"
12+
13+
int main (void)
14+
{
15+
...
16+
}
17+
```
18+
19+
Including a header file produces the same results as copying the header file
20+
into each source file that needs it. Such copying would be time-consuming
21+
and error-prone. With a header file, the related declarations appear
22+
in only one place. If they need to be changed, they can be changed in one
23+
place, and programs that include the header file will automatically use the
24+
new version when next recompiled. The header file eliminates the labor of
25+
finding and changing all the copies as well as the risk that a failure to
26+
find one copy will result in inconsistencies within a program.
27+
28+
In C, the usual convention is to give header files names that end with `.h'.
29+
It is most portable to use only letters, digits, dashes, and underscores in
30+
header file names, and at most one dot.
31+
32+
Read more about using header files in official GCC documentation:
33+
34+
* Include Syntax
35+
* Include Operation
36+
* Once-Only Headers
37+
* Computed Includes
38+
39+
https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
2+
This directory is intended for project specific (private) libraries.
3+
PlatformIO will compile them to static libraries and link into executable file.
4+
5+
The source code of each library should be placed in a an own separate directory
6+
("lib/your_library_name/[here are source files]").
7+
8+
For example, see a structure of the following two libraries `Foo` and `Bar`:
9+
10+
|--lib
11+
| |
12+
| |--Bar
13+
| | |--docs
14+
| | |--examples
15+
| | |--src
16+
| | |- Bar.c
17+
| | |- Bar.h
18+
| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html
19+
| |
20+
| |--Foo
21+
| | |- Foo.c
22+
| | |- Foo.h
23+
| |
24+
| |- README --> THIS FILE
25+
|
26+
|- platformio.ini
27+
|--src
28+
|- main.c
29+
30+
and a contents of `src/main.c`:
31+
```
32+
#include <Foo.h>
33+
#include <Bar.h>
34+
35+
int main (void)
36+
{
37+
...
38+
}
39+
40+
```
41+
42+
PlatformIO Library Dependency Finder will find automatically dependent
43+
libraries scanning project source files.
44+
45+
More information about PlatformIO Library Dependency Finder
46+
- https://docs.platformio.org/page/librarymanager/ldf.html
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
; PlatformIO Project Configuration File
2+
;
3+
; Build options: build flags, source filter
4+
; Upload options: custom upload port, speed and extra flags
5+
; Library options: dependencies, extra library storages
6+
; Advanced options: extra scripting
7+
;
8+
; Please visit documentation for the other options and examples
9+
; https://docs.platformio.org/page/projectconf.html
10+
11+
[env:nodemcuv2]
12+
platform = espressif8266
13+
board = nodemcuv2
14+
framework = arduino
15+
monitor_speed = 115200
16+
lib_deps =
17+
adafruit/Adafruit SSD1306@^2.4.4
18+
tectiv3/Adafruit-SSD1331@0.0.0-alpha+sha.488737cb7a
Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
/**************************************************************************
2+
This is an example for our Monochrome OLEDs based on SSD1306 drivers
3+
4+
Pick one up today in the adafruit shop!
5+
------> http://www.adafruit.com/category/63_98
6+
7+
This example is for a 128x64 pixel display using I2C to communicate
8+
3 pins are required to interface (two I2C and one reset).
9+
10+
Adafruit invests time and resources providing this open
11+
source code, please support Adafruit and open-source
12+
hardware by purchasing products from Adafruit!
13+
14+
Written by Limor Fried/Ladyada for Adafruit Industries,
15+
with contributions from the open source community.
16+
BSD license, check license.txt for more information
17+
All text above, and the splash screen below must be
18+
included in any redistribution.
19+
**************************************************************************/
20+
21+
#include <Wire.h>
22+
#include <Adafruit_GFX.h>
23+
#include <Adafruit_SSD1306.h>
24+
#include <Adafruit_I2CDevice.h>
25+
#include <math.h>
26+
27+
#define SCREEN_WIDTH 128 // OLED display width, in pixels
28+
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
29+
30+
// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
31+
// The pins for I2C are defined by the Wire-library.
32+
// On an arduino UNO: A4(SDA), A5(SCL)
33+
// On an arduino MEGA 2560: 20(SDA), 21(SCL)
34+
// On an arduino LEONARDO: 2(SDA), 3(SCL), ...
35+
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
36+
#define OLED_RESET -1 // Reset pin # (or -1 if sharing Arduino reset pin)
37+
38+
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
39+
40+
void rotVec2(float vec[2], float alpha, float *vecRot)
41+
{
42+
float x = vec[0];
43+
float y = vec[1];
44+
float xRot = x * cos(alpha) - y * sin(alpha);
45+
float yRot = x * sin(alpha) + y * cos(alpha);
46+
vecRot[0] = xRot;
47+
vecRot[1] = yRot;
48+
}
49+
50+
const int nbExtremyties = 5;
51+
const int dim = 2;
52+
const int16_t yMax = SCREEN_HEIGHT - 1;
53+
54+
void nextKochSnoflake(float x0Screen,
55+
float y0Screen,
56+
float x1Screen,
57+
float y1Screen,
58+
float ptPath[nbExtremyties][dim])
59+
{
60+
float x0Cart = x0Screen;
61+
float x1Cart = x1Screen;
62+
float y0Cart = -y0Screen + yMax;
63+
float y1Cart = -y1Screen + yMax;
64+
65+
float vect[2] = {x1Cart - x0Cart, y1Cart - y0Cart};
66+
float alpha = atan2(vect[1], vect[0]);
67+
float vectLen = sqrt(vect[0] * vect[0] + vect[1] * vect[1]);
68+
float xLen = vectLen;
69+
float xInc = xLen / 3;
70+
float yMid = sqrt(3) / 2 * xInc;
71+
72+
float v[4][2] = {{xInc, 0},
73+
{xInc / 2, yMid},
74+
{xInc / 2, -yMid},
75+
{xInc, 0}};
76+
77+
float vRot[4][2] = {{0, 0},
78+
{0, 0},
79+
{0, 0},
80+
{0, 0}};
81+
82+
for (int i = 0; i < 4; ++i)
83+
{
84+
rotVec2(v[i], alpha, vRot[i]);
85+
}
86+
87+
// Flip y to adapt screen coordinate system
88+
for (int i = 0; i < 4; ++i)
89+
{
90+
vRot[i][1] = -vRot[i][1];
91+
}
92+
93+
ptPath[0][0] = x0Screen;
94+
ptPath[0][1] = y0Screen;
95+
for (int i = 0; i < 4; ++i)
96+
{
97+
ptPath[i + 1][0] = ptPath[i][0] + vRot[i][0];
98+
ptPath[i + 1][1] = ptPath[i][1] + vRot[i][1];
99+
}
100+
}
101+
102+
int sumNbSegment(int order)
103+
{
104+
if (order < 1)
105+
{
106+
return 1;
107+
}
108+
else
109+
{
110+
int sum = 0;
111+
for (int i = 0; i < order; ++i)
112+
{
113+
sum += pow(4, i);
114+
}
115+
return sum;
116+
}
117+
}
118+
119+
void kochSnowflake(int16_t x0Screen,
120+
int16_t y0Screen,
121+
int16_t x1Screen,
122+
int16_t y1Screen,
123+
int order)
124+
{
125+
display.clearDisplay();
126+
127+
printf("order %d\n", order);
128+
const int totalNbSegment = sumNbSegment(order);
129+
// printf("totalNbSegment %d\n", totalNbSegment);
130+
131+
int nbSegmentPerOrder[order];
132+
for (int i = 0; i < order; ++i)
133+
{
134+
nbSegmentPerOrder[i] = pow(4, i);
135+
// printf("nbSegmentPerOrder[%d]: %d\n", i, nbSegmentPerOrder[i]);
136+
}
137+
138+
int parentMapping[totalNbSegment][2];
139+
for (int j = 1; j < totalNbSegment; ++j)
140+
{
141+
int toSub = 0;
142+
int currentTotal = 0;
143+
int iBreak = 0;
144+
for (int i = 0; i < order; ++i)
145+
{
146+
currentTotal += nbSegmentPerOrder[i];
147+
if (j < currentTotal)
148+
{
149+
toSub = currentTotal - nbSegmentPerOrder[i];
150+
iBreak = std::max(i - 1, 0);
151+
break;
152+
}
153+
}
154+
int idxParentOffset = 0;
155+
for (int i = 0; i < iBreak; ++i)
156+
{
157+
idxParentOffset += nbSegmentPerOrder[i];
158+
}
159+
160+
int jNormalised = (j - toSub);
161+
int quot = jNormalised / 4;
162+
int parentIdx = quot + idxParentOffset;
163+
int subIdx = jNormalised % 4;
164+
parentMapping[j][0] = parentIdx;
165+
parentMapping[j][1] = subIdx;
166+
}
167+
// printf("\n");
168+
169+
// Initialisation of path points
170+
float ptPath[totalNbSegment][nbExtremyties][dim];
171+
nextKochSnoflake(x0Screen,
172+
y0Screen,
173+
x1Screen,
174+
y1Screen, ptPath[0]);
175+
176+
for (int j = 1; j < totalNbSegment; ++j)
177+
{
178+
179+
const int parentIdx = parentMapping[j][0];
180+
const int subIdx = parentMapping[j][1];
181+
nextKochSnoflake(ptPath[parentIdx][subIdx][0],
182+
ptPath[parentIdx][subIdx][1],
183+
ptPath[parentIdx][subIdx + 1][0],
184+
ptPath[parentIdx][subIdx + 1][1],
185+
ptPath[j]);
186+
}
187+
188+
int jStart = 0;
189+
int jEnd = 0;
190+
for (int i = 0; i < order; ++i)
191+
{
192+
if (i < (order - 1))
193+
{
194+
jStart += nbSegmentPerOrder[i];
195+
}
196+
jEnd += nbSegmentPerOrder[i];
197+
}
198+
199+
for (int j = jStart; j < jEnd; ++j)
200+
{
201+
for (int i = 0; i < 4; ++i)
202+
{
203+
const int16_t i0 = i;
204+
const int16_t i1 = i0 + 1;
205+
display.drawLine(ptPath[j][i0][0], ptPath[j][i0][1],
206+
ptPath[j][i1][0], ptPath[j][i1][1], SSD1306_WHITE);
207+
display.display();
208+
delay(100);
209+
}
210+
}
211+
}
212+
213+
void setup()
214+
{
215+
Serial.begin(115200);
216+
217+
while (!Serial)
218+
;
219+
220+
// SSD1306_SWITCHCAPVCC = generate display voltage from 3.3V internally
221+
if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS))
222+
{
223+
Serial.println(F("SSD1306 allocation failed"));
224+
for (;;)
225+
; // Don't proceed, loop forever
226+
}
227+
228+
int16_t x0Screen;
229+
int16_t x1Screen;
230+
int16_t y0Screen;
231+
int16_t y1Screen;
232+
for (;;)
233+
{
234+
x0Screen = 1;
235+
x1Screen = x0Screen + 42 * 3;
236+
y0Screen = yMax - 14;
237+
y1Screen = y0Screen - 0;
238+
for (int i = 1; i < 4; ++i)
239+
{
240+
kochSnowflake(x0Screen,
241+
y0Screen,
242+
x1Screen,
243+
y1Screen, i);
244+
delay(1000);
245+
}
246+
}
247+
}
248+
249+
void loop()
250+
{
251+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
2+
This directory is intended for PlatformIO Unit Testing and project tests.
3+
4+
Unit Testing is a software testing method by which individual units of
5+
source code, sets of one or more MCU program modules together with associated
6+
control data, usage procedures, and operating procedures, are tested to
7+
determine whether they are fit for use. Unit testing finds problems early
8+
in the development cycle.
9+
10+
More information about PlatformIO Unit Testing:
11+
- https://docs.platformio.org/page/plus/unit-testing.html

0 commit comments

Comments
 (0)