Skip to content

Commit 6f94fe0

Browse files
authored
Merge pull request #48 from saxbophone/develop
v0.11.1
2 parents 0a0e494 + 2bfdcfe commit 6f94fe0

File tree

10 files changed

+120
-43
lines changed

10 files changed

+120
-43
lines changed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
cmake_minimum_required(VERSION 3.0)
33
enable_language(C CXX)
44

5-
project(saxbospiral VERSION 0.11.0 LANGUAGES C)
5+
project(saxbospiral VERSION 0.11.1 LANGUAGES C)
66
set(CMAKE_C_STANDARD 99)
77
set(CMAKE_C_STANDARD_REQUIRED ON)
88
set(

saxbospiral.png

-2 Bytes
Loading

saxbospiral/saxbospiral.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,14 @@ const version_t VERSION = {
1212
.patch = SAXBOSPIRAL_VERSION_PATCH,
1313
};
1414

15+
/*
16+
* computes a version_hash_t for a given version_t,
17+
* to be used for indexing and ordering
18+
*/
19+
version_hash_t version_hash(version_t version) {
20+
return (version.major * 65536) + (version.minor * 256) + version.patch;
21+
}
22+
1523
// vector direction constants
1624
const vector_t VECTOR_DIRECTIONS[4] = {
1725
// UP RIGHT DOWN LEFT

saxbospiral/saxbospiral.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,15 @@ typedef struct version_t {
2222

2323
extern const version_t VERSION;
2424

25+
// used for indexing and comparing different versions in order
26+
typedef uint32_t version_hash_t;
27+
28+
/*
29+
* computes a version_hash_t for a given version_t,
30+
* to be used for indexing and ordering
31+
*/
32+
version_hash_t version_hash(version_t version);
33+
2534
// type for representing a cartesian direction
2635
typedef uint8_t direction_t;
2736

saxbospiral/serialise.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,20 @@ load_spiral(buffer_t buffer) {
3535
(strncmp((char *)buffer.bytes, "SAXBOSPIRAL", 11) == 0)
3636
&& (buffer.size >= FILE_HEADER_SIZE + LINE_T_PACK_SIZE)
3737
) {
38-
// good to go
39-
// TODO: Add checks for buffer data version compatibility
40-
/*
41-
version_t data_version = {
42-
buffer.bytes[12], buffer.bytes[13], buffer.bytes[13],
38+
// grab file version from header
39+
version_t buffer_version = {
40+
.major = buffer.bytes[12],
41+
.minor = buffer.bytes[13],
42+
.patch = buffer.bytes[14],
4343
};
44-
*/
44+
// we don't accept anything over v0.11.x, so the max is v0.11.255
45+
version_t max_version = { .major = 0, .minor = 11, .patch = 255, };
46+
// check for version compatibility
47+
if(version_hash(buffer_version) > version_hash(max_version)) {
48+
// check failed
49+
return output;
50+
}
51+
// good to go
4552
// get size of spiral object contained in buffer
4653
size_t spiral_size = 0;
4754
for(size_t i = 0; i < 8; i++) {

saxbospiral/solve.c

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,11 @@ spiral_collides(spiral_t spiral, size_t index) {
7575
}
7676

7777
/*
78-
* given a spiral struct that is known to collide and the index of the 'last'
79-
* segment in the spiral (i.e. the one that was found to be colliding), return
80-
* a suggested length to set the segment before this line to.
78+
* given a spiral struct that is known to collide, the index of the 'last'
79+
* segment in the spiral (i.e. the one that was found to be colliding) and a
80+
* perfection threshold (-1 for no perfection, or otherwise the maximmum line
81+
* length at which to allow aggressive optimisation), return a suggested length
82+
* to set the segment before this line to.
8183
*
8284
* NOTE: This function is not guaranteed to make suggestions that will not
8385
* collide. Every suggestion that is followed should then have the spiral
@@ -91,21 +93,31 @@ spiral_collides(spiral_t spiral, size_t index) {
9193
* line before the newly plotted line.
9294
*/
9395
static length_t
94-
suggest_resize(spiral_t spiral, size_t index) {
96+
suggest_resize(spiral_t spiral, size_t index, int perfection_threshold) {
9597
// check if collides or not, return same size if no collision
9698
if(spiral.collides != -1) {
9799
/*
98-
* if the colliding line's length is greater than 1, we cannot make any
99-
* intelligent suggestions on the length to extend the previous line to
100-
* (without the high likelihood of creating a line that wastes space),
101-
* so we just return the previous line's length +1
100+
* if the perfection threshold is -1, then we can just use our suggestion,
101+
* as perfection is disabled.
102+
* otherwise, if the colliding line's length is greater than our
103+
* perfection threshold, we cannot make any intelligent suggestions on
104+
* the length to extend the previous line to (without the high
105+
* likelihood of creating a line that wastes space), so we just return
106+
* the previous line's length +1
102107
*/
103-
if(spiral.lines[index].length > 1) {
108+
if(
109+
(perfection_threshold != -1) &&
110+
(spiral.lines[index].length > (length_t)perfection_threshold)
111+
) {
104112
return spiral.lines[index - 1].length + 1;
105113
}
106114
// store the 'previous' and 'rigid' lines.
107115
line_t p = spiral.lines[index - 1];
108116
line_t r = spiral.lines[spiral.collides];
117+
// if pr and r are not parallel, we can return early
118+
if((p.direction % 2) != (r.direction % 2)) {
119+
return spiral.lines[index - 1].length + 1;
120+
}
109121
// create variables to store the start and end co-ords of these lines
110122
co_ord_t pa, pb, ra, rb;
111123
/*
@@ -155,11 +167,15 @@ suggest_resize(spiral_t spiral, size_t index) {
155167

156168
/*
157169
* given a spiral struct, the index of one of it's lines and a target length to
158-
* set that line to, attempt to set the target line to that length,
159-
* back-tracking to resize the previous line if it collides.
170+
* set that line to and a perfection threshold (-1 for no perfection, or
171+
* otherwise the maximmum line length at which to allow aggressive optimisation)
172+
* attempt to set the target line to that length, back-tracking to resize the
173+
* previous line if it collides.
160174
*/
161175
spiral_t
162-
resize_spiral(spiral_t spiral, size_t index, length_t length) {
176+
resize_spiral(
177+
spiral_t spiral, size_t index, uint32_t length, int perfection_threshold
178+
) {
163179
/*
164180
* setup state variables, these are used in place of recursion for managing
165181
* state of which line is being resized, and what size it should be.
@@ -185,7 +201,9 @@ resize_spiral(spiral_t spiral, size_t index, length_t length) {
185201
* function to get the suggested length to resize the previous
186202
* segment to
187203
*/
188-
current_length = suggest_resize(spiral, current_index);
204+
current_length = suggest_resize(
205+
spiral, current_index, perfection_threshold
206+
);
189207
current_index--;
190208
} else if(current_index != index) {
191209
/*
@@ -206,22 +224,24 @@ resize_spiral(spiral_t spiral, size_t index, length_t length) {
206224
}
207225

208226
/*
209-
* given a spiral for which the length of all its lines are not yet known,
210-
* calculate the length needed for each line in the spiral (to avoid line overlap)
211-
* and store these in a spiral struct and return that
227+
* given a spiral for which the length of all its lines are not yet known and
228+
* a perfection threshold (-1 for no perfection, or otherwise the maximmum line
229+
* length at which to allow aggressive optimisation) calculate the length needed
230+
* for each line in the spiral (to avoid line overlap) and store these in a
231+
* spiral struct and return that
212232
*/
213233
spiral_t
214-
plot_spiral(spiral_t input) {
234+
plot_spiral(spiral_t spiral, int perfection_threshold) {
215235
// allocate new struct as copy of input struct
216-
spiral_t output = { .size = input.size, };
236+
spiral_t output = { .size = spiral.size, };
217237
output.lines = calloc(sizeof(line_t), output.size);
218238
// copy across the spiral lines
219239
for(size_t i = 0; i < output.size; i++) {
220-
output.lines[i] = input.lines[i];
240+
output.lines[i] = spiral.lines[i];
221241
}
222242
// calculate the length of each line
223243
for(size_t i = 0; i < output.size; i++) {
224-
output = resize_spiral(output, i, 1);
244+
output = resize_spiral(output, i, 1, perfection_threshold);
225245
}
226246
// free the co_ord_cache member's dynamic memory if required
227247
if(output.co_ord_cache.co_ords.size > 0) {

saxbospiral/solve.h

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -11,20 +11,26 @@ extern "C"{
1111
#endif
1212

1313
/*
14-
* given a spiral for which the length of all its lines are not yet known,
15-
* calculate the length needed for each line in the spiral (to avoid line overlap)
16-
* and store these in a spiral struct and return that
14+
* given a spiral for which the length of all its lines are not yet known and
15+
* a perfection threshold (-1 for no perfection, or otherwise the maximmum line
16+
* length at which to allow aggressive optimisation) calculate the length needed
17+
* for each line in the spiral (to avoid line overlap) and store these in a
18+
* spiral struct and return that
1719
*/
1820
spiral_t
19-
plot_spiral(spiral_t spiral);
21+
plot_spiral(spiral_t spiral, int perfection_threshold);
2022

2123
/*
2224
* given a spiral struct, the index of one of it's lines and a target length to
23-
* set that line to, attempt to set the target line to that length,
24-
* back-tracking to resize the previous line if it collides.
25+
* set that line to and a perfection threshold (-1 for no perfection, or
26+
* otherwise the maximmum line length at which to allow aggressive optimisation)
27+
* attempt to set the target line to that length, back-tracking to resize the
28+
* previous line if it collides.
2529
*/
2630
spiral_t
27-
resize_spiral(spiral_t spiral, size_t index, uint32_t length);
31+
resize_spiral(
32+
spiral_t spiral, size_t index, uint32_t length, int perfection_threshold
33+
);
2834

2935
#ifdef __cplusplus
3036
} // extern "C"

sxp.c

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ buffer_to_file(buffer_t * buffer, FILE * file_handle) {
8585
*/
8686
bool
8787
run(
88-
bool prepare, bool generate, bool render,
88+
bool prepare, bool generate, bool render, bool perfect, int perfect_threshold,
8989
const char * input_file_path, const char * output_file_path
9090
) {
9191
// get input file handle
@@ -115,21 +115,31 @@ run(
115115
fprintf(stderr, "%s\n", "Couldn't read input file");
116116
return false;
117117
}
118+
// resolve perfection threshold - set to -1 if disabled completely
119+
int perfection = (perfect == false) ? -1 : perfect_threshold;
118120
if(prepare) {
119121
// we must build spiral from raw file first
120122
spiral_t spiral = init_spiral(input_buffer);
121123
if(generate) {
122124
// now we must plot all lines from spiral file
123-
spiral = plot_spiral(spiral);
125+
spiral = plot_spiral(spiral, perfection);
124126
}
125127
// TODO: Currently unable to generate and render all in one invocation
126128
// dump spiral
127129
output_buffer = dump_spiral(spiral);
128130
} else if(generate) {
129131
// try and load a spiral struct from input file
130132
spiral_t spiral = load_spiral(input_buffer);
133+
// the spiral size will be set to 0 if buffer data was invalid
134+
if(spiral.size == 0) {
135+
fprintf(
136+
stderr, "ERROR - File data was invalid (not a format accepted "
137+
"by SAXBOSPIRAL " SAXBOSPIRAL_VERSION_STRING ")\n"
138+
);
139+
return false;
140+
}
131141
// we must plot all lines from spiral file
132-
spiral = plot_spiral(spiral);
142+
spiral = plot_spiral(spiral, perfection);
133143
// dump spiral
134144
output_buffer = dump_spiral(spiral);
135145
} else if(render) {
@@ -189,18 +199,31 @@ main(int argc, char * argv[]) {
189199
"r", "render", "render the input spiral to an image (cannot be used "
190200
"with -p or -g options)"
191201
);
202+
struct arg_lit * perfect = arg_lit0(
203+
"D", "disable-perfection", "allow aggressive optimisations to take "
204+
"place for a massive speed boost, at the cost of producing spirals that"
205+
" are imperfect and waste some space with oversized lines"
206+
);
207+
struct arg_int * perfect_threshold = arg_int0(
208+
"d", "perfection-threshold", NULL, "set a threshold above which length "
209+
"lines are not optimised (default value is 1, which still yields "
210+
"results)"
211+
);
192212
// input file path option
193213
struct arg_file * input = arg_file0(
194-
"i", "input", "<path>", "input file path"
214+
"i", "input", NULL, "input file path"
195215
);
196216
// output file path option
197217
struct arg_file * output = arg_file0(
198-
"o", "output", "<path>", "output file path"
218+
"o", "output", NULL, "output file path"
199219
);
200220
// argtable boilerplate
201221
struct arg_end * end = arg_end(20);
202222
void * argtable[] = {
203-
help, version, prepare, generate, render, input, output, end,
223+
help, version,
224+
prepare, generate, render,
225+
perfect, perfect_threshold,
226+
input, output, end,
204227
};
205228
const char * program_name = "sxp";
206229
// check argtable members were allocated successfully
@@ -211,8 +234,10 @@ main(int argc, char * argv[]) {
211234
);
212235
status_code = 2;
213236
}
237+
// set default value of perfect_threshold argument
238+
perfect_threshold->ival[0] = 1;
214239
// parse arguments
215-
int count_errors = arg_parse(argc,argv,argtable);
240+
int count_errors = arg_parse(argc, argv, argtable);
216241
// if we asked for the version, show it
217242
if(version->count > 0) {
218243
printf("Saxbospiral " SAXBOSPIRAL_VERSION_STRING "\n");
@@ -240,6 +265,8 @@ main(int argc, char * argv[]) {
240265
(prepare->count > 0) ? true : false,
241266
(generate->count > 0) ? true : false,
242267
(render->count > 0) ? true : false,
268+
(perfect->count > 0) ? false : true,
269+
perfect_threshold->ival[0],
243270
* input->filename,
244271
* output->filename
245272
);

sxp.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ buffer_to_file(buffer_t * buffer, FILE * file_handle);
3838
*/
3939
bool
4040
run(
41-
bool prepare, bool generate, bool render,
41+
bool prepare, bool generate, bool render, bool perfect, int perfect_threshold,
4242
const char * input_file_path, const char * output_file_path
4343
);
4444

tests.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,7 @@ test_plot_spiral() {
206206
}
207207

208208
// call init_spiral with buffer and store result
209-
spiral_t output = plot_spiral(input);
209+
spiral_t output = plot_spiral(input, 1);
210210

211211
// compare with expected struct
212212
for(uint8_t i = 0; i < 16; i++) {

0 commit comments

Comments
 (0)