summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile26
-rw-r--r--examples/quad.c1
-rw-r--r--examples/quad2.c101
-rw-r--r--examples/stacked.c2
-rw-r--r--examples/triangle_tip.c6
-rw-r--r--inc/cad/construction.h3
-rw-r--r--inc/cad/debug.h11
-rw-r--r--inc/cad/solve.h1
-rw-r--r--inc/cad/svg.h3
-rw-r--r--src/construction.c20
-rw-r--r--src/debug.c2
-rw-r--r--src/main.c177
-rw-r--r--src/solve.c141
-rw-r--r--src/svg.c158
14 files changed, 391 insertions, 261 deletions
diff --git a/Makefile b/Makefile
index 49823c8..0d9dba1 100644
--- a/Makefile
+++ b/Makefile
@@ -7,13 +7,10 @@ OBJDIR ?= obj
TSTDIR ?= test
EXMDIR ?= examples
-PKGS = sdl2 opengl
-LIBS = -lm $(shell pkg-config --libs $(PKGS))
INCS = -Ithirdparty/cglm/include -Ithirdparty/ -Iinc/
-CFLAGS ?= -D_FORTIFY_SOURCE=2 -Wall -Werror -Wno-error=unused-variable -g -Og
-CFLAGS += -std=gnu23 -fms-extensions -flto $(shell pkg-config --cflags $(PKGS)) -DCIMGUI_USE_OPENGL3 -DCIMGUI_USE_SDL2
-CXXFLAGS += -flto $(shell pkg-config --cflags $(PKGS)) -DCIMGUI_USE_OPENGL3 -DCIMGUI_USE_SDL2 -DIMGUI_IMPL_API='extern "C"'
+CFLAGS ?= -Wall -Werror -Wno-error=unused-variable -g -O0 -lm
+CFLAGS += -std=gnu23 -fms-extensions -flto
APP_MAIN_SOURCES = $(SRCDIR)/main.c
APP_MAIN_OBJS = $(APP_MAIN_SOURCES:%.c=$(OBJDIR)/%.o)
@@ -33,8 +30,6 @@ EXM_OBJS = $(EXM_SOURCES:%.c=$(OBJDIR)/%.o)
EXM_DEPS = $(EXM_OBJS:%.o=%.d)
EXM_APPS = $(EXM_SOURCES:%.c=$(OBJDIR)/%)
-IMGUI_OBJS = $(OBJDIR)/thirdparty/cimgui/imgui/backends/imgui_impl_sdl2.o $(OBJDIR)/thirdparty/cimgui/imgui/backends/imgui_impl_opengl3.o
-
-include $(APP_DEPS) $(APP_MAIN_DEPS) $(TST_DEPS) $(EXM_DEPS)
# We don't really need to run the tests for bear to record them
@@ -42,14 +37,8 @@ compile_commands.json: clean Makefile $(APP_SOURCES)
@rm -f "$@"
bear -- make main
-.PHONY: thirdparty/cimgui/cimgui.so
-thirdparty/cimgui/cimgui.so:
- make -C thirdparty/cimgui
-
-LIBS += -Lthirdparty/cimgui -Wl,-rpath,'$$ORIGIN/thirdparty/cimgui' -lcimgui -lstdc++
-
-main: $(APP_MAIN_OBJS) $(APP_OBJS) thirdparty/cimgui/cimgui.so $(IMGUI_OBJS)
- $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(APP_MAIN_OBJS) $(APP_OBJS) $(IMGUI_OBJS) $(LIBS)
+main: $(APP_MAIN_OBJS) $(APP_OBJS)
+ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $(APP_MAIN_OBJS) $(APP_OBJS)
$(OBJDIR)/%.o: %.c
@mkdir -p $(dir $@)
@@ -61,7 +50,7 @@ $(OBJDIR)/test/%: $(OBJDIR)/test/%.o $(APP_OBJS)
$(OBJDIR)/examples/%: $(OBJDIR)/examples/%.o $(APP_OBJS)
@mkdir -p $(dir $@)
- $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $< $(APP_OBJS) $(LIBS)
+ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $< $(APP_OBJS)
clean:
@rm -rf $(OBJDIR)
@@ -76,8 +65,3 @@ examples: $(EXM_APPS)
.DEFAULT_GOAL := all
all: main test examples
-
-# Imgui specific compile rules
-$(OBJDIR)/%.o: %.cpp
- @mkdir -p $(dir $@)
- $(CXX) $(CXXFLAGS) $(INCS) -Ithirdparty/cimgui/imgui/ -MMD -o $@ -c $<
diff --git a/examples/quad.c b/examples/quad.c
index a22e872..b689f61 100644
--- a/examples/quad.c
+++ b/examples/quad.c
@@ -26,6 +26,7 @@ void draw_from_constraints(struct constraints *c, struct topology *t, struct can
begin_drawing(cv);
draw_topology(cv, t);
draw_constraints(cv, c);
+ draw_elements(cv, &drawing);
end_drawing(cv);
free_drawing(&drawing);
diff --git a/examples/quad2.c b/examples/quad2.c
new file mode 100644
index 0000000..fd465fd
--- /dev/null
+++ b/examples/quad2.c
@@ -0,0 +1,101 @@
+#include "cad.h"
+#include "cad/svg.h"
+#include "cad/debug.h"
+
+void draw_from_constraints(struct constraints *c, struct topology *t, struct canvas *cv) {
+ struct drawing drawing = {};
+ struct subassembly assemblies[16] = {};
+ size_t assemblies_num;
+ bool rc = solve_constraints(c, &drawing, assemblies, &assemblies_num);
+ assert(rc);
+
+ // Copy over all the parameter values to a new array
+ // @PERF: Maybe we should just store them in a separate array to start with
+ double *params = malloc(sizeof(double) * (c->length));
+ for(size_t i = 0; i < c->length; i++) {
+ params[i] = c->elements[i].v;
+ }
+
+ place_points(&drawing, params);
+ dump_program(&drawing, params);
+ free(params);
+
+ reconstruct_drawing(c, assemblies, &assemblies_num);
+ print_subassemblies(c, assemblies, assemblies_num);
+
+ begin_drawing(cv);
+ draw_topology(cv, t);
+ draw_constraints(cv, c);
+ draw_elements(cv, &drawing);
+ end_drawing(cv);
+
+ free_drawing(&drawing);
+}
+
+int main(int argc, char *argv[]) {
+ struct constraints constraints = {};
+ struct topology topo = {};
+
+ struct component bp = {.type = COM_POINT};
+ struct component yx = {.type = COM_LINE};
+
+ struct component p1 = {.type = COM_POINT};
+ struct component p2 = {.type = COM_POINT};
+ struct component p3 = {.type = COM_POINT};
+ struct component p4 = {.type = COM_POINT};
+
+ struct component l1 = {.type = COM_LINE};
+ struct component l2 = {.type = COM_LINE};
+ struct component l3 = {.type = COM_LINE};
+ struct component l4 = {.type = COM_LINE};
+
+ add_constraint(&constraints, (struct constraint[]){
+ POINT_ON_LINE(&bp, &yx),
+
+ PP_DISTANCE(&p1, &bp, 10),
+ PL_DISTANCE(&p1, &yx, 5),
+
+ LL_ANGLE(&l2, &yx, DEG(30)),
+
+ PP_DISTANCE(&p1, &p2, 10),
+ PP_DISTANCE(&p4, &p1, 20),
+
+ POINT_ON_LINE(&p1, &l1),
+ POINT_ON_LINE(&p2, &l1),
+
+ POINT_ON_LINE(&p2, &l2),
+ POINT_ON_LINE(&p3, &l2),
+
+ POINT_ON_LINE(&p3, &l3),
+ POINT_ON_LINE(&p4, &l3),
+
+ POINT_ON_LINE(&p4, &l4),
+ POINT_ON_LINE(&p1, &l4),
+
+ LL_ANGLE(&l4, &l1, DEG(90)),
+ LL_ANGLE(&l2, &l3, DEG(90)),
+ LL_ANGLE(&l3, &l4, DEG(90)),
+
+ CEND(),
+ });
+
+ add_fragment(&topo, (struct topology_elem[]){
+ TOPO_MOVETO(&p1),
+ TOPO_LINETO(&p2),
+ TOPO_LINETO(&p3),
+ TOPO_LINETO(&p4),
+ TOPO_LINETO(&p1),
+
+ TOPO_END(),
+ });
+
+ struct canvas canvas = {
+ .state = CANVAS_INIT,
+ .f = stdout,
+ };
+
+ draw_from_constraints(&constraints, &topo, &canvas);
+
+ free_constraints(&constraints);
+ return 0;
+}
diff --git a/examples/stacked.c b/examples/stacked.c
index aeee9ee..0d52898 100644
--- a/examples/stacked.c
+++ b/examples/stacked.c
@@ -76,11 +76,13 @@ void draw_from_constraints(struct constraints *c, struct topology *t, struct can
}
place_points(&drawing, params);
+ dump_program(&drawing, params);
free(params);
begin_drawing(cv);
draw_topology(cv, t);
draw_constraints(cv, c);
+ // draw_elements(cv, &drawing);
end_drawing(cv);
free_drawing(&drawing);
diff --git a/examples/triangle_tip.c b/examples/triangle_tip.c
index 232b16e..87875de 100644
--- a/examples/triangle_tip.c
+++ b/examples/triangle_tip.c
@@ -17,14 +17,16 @@ void draw_from_constraints(struct constraints *c, struct topology *t, struct can
}
place_points(&drawing, params);
- free(params);
reconstruct_drawing(c, assemblies, &assemblies_num);
print_subassemblies(c, assemblies, assemblies_num);
+ // dump_program(&drawing, params);
+ free(params);
begin_drawing(cv);
draw_topology(cv, t);
draw_constraints(cv, c);
+ // draw_elements(cv, &drawing);
end_drawing(cv);
free_drawing(&drawing);
@@ -66,7 +68,7 @@ int main(int argc, char *argv[]) {
POINT_ON_LINE(&p5, &t2base),
// The edge they don't share is constrained
- LL_ANGLE(&t1bas2, &t2base, DEG(70)),
+ LL_ANGLE(&t1bas2, &t2base, DEG(80)),
CEND(),
});
diff --git a/inc/cad/construction.h b/inc/cad/construction.h
index ea784cf..cb6b2bc 100644
--- a/inc/cad/construction.h
+++ b/inc/cad/construction.h
@@ -64,6 +64,7 @@ struct command {
enum operation op;
uint8_t root;
bool hidden;
+ bool placed;
// Only used for input commands
size_t index;
@@ -90,6 +91,8 @@ struct drawing {
struct command *error;
};
+void normalize_line(struct line *line);
+
struct element* insert_cmd(struct drawing *drawing, struct command cmd);
void place_points(struct drawing *drawing, double inputs[]);
void dump_program(struct drawing *drawing, double inputs[]);
diff --git a/inc/cad/debug.h b/inc/cad/debug.h
index b08463f..cad9b3c 100644
--- a/inc/cad/debug.h
+++ b/inc/cad/debug.h
@@ -2,4 +2,15 @@
#include <stdint.h>
+#include <SDL2/SDL.h>
+
+#define igGetIO igGetIO_Nil
+
void print_subassemblies(struct constraints *c, struct subassembly *assemblies, size_t assemblies_num);
+
+struct gui {
+ SDL_Window *window;
+ SDL_GLContext gl_context;
+};
+
+void show_debug_ui(struct constraints *c, struct subassembly *assemblies, size_t assemblies_num, struct drawing* draw);
diff --git a/inc/cad/solve.h b/inc/cad/solve.h
index 9a0c56d..dad3edb 100644
--- a/inc/cad/solve.h
+++ b/inc/cad/solve.h
@@ -12,6 +12,7 @@ enum component_type {
struct subassembly;
struct component {
+ uint16_t id;
enum component_type type;
struct element *e;
diff --git a/inc/cad/svg.h b/inc/cad/svg.h
index 5bfce83..c282c0e 100644
--- a/inc/cad/svg.h
+++ b/inc/cad/svg.h
@@ -14,10 +14,12 @@ enum LineStyle {
enum CanvasState {
CANVAS_INIT,
CANVAS_DRAWING,
+ CANVAS_COORDINATE,
};
struct canvas {
enum CanvasState state;
+ vec2 next_offset;
FILE *f;
};
@@ -30,5 +32,6 @@ void plot_text(struct canvas *canvas, struct point p, double angle, char* str);
void begin_drawing(struct canvas *canvas);
void draw_constraints(struct canvas *canvas, struct constraints *constraints);
+void draw_elements(struct canvas *canvas, struct drawing *drawing);
void draw_topology(struct canvas *canvas, struct topology *topo);
void end_drawing(struct canvas *canvas);
diff --git a/src/construction.c b/src/construction.c
index f175f79..f2a473a 100644
--- a/src/construction.c
+++ b/src/construction.c
@@ -35,6 +35,12 @@ bool circle_line_intersect(struct circle circle, struct line line, uint8_t root,
return true;
}
+void normalize_line(struct line *line) {
+ double mag = glm_vec2_norm(line->norm);
+ glm_vec2_scale(line->norm, 1.0f/mag, line->norm);
+ line->C /= mag;
+}
+
void line_through_points(struct point p1, struct point p2, struct line* l) {
l->norm[0] = p1.pos[1] - p2.pos[1];
l->norm[1] = p2.pos[0] - p1.pos[0];
@@ -141,7 +147,9 @@ static void transform_part(struct command *cmd, const struct command *last_cmd,
}
void dump_program(struct drawing *drawing, double inputs[]) {
+ size_t i = 0;
for(struct command *current = drawing->root; current != NULL; current = current->next) {
+ fprintf(stderr, "%ld ", i++);
switch(current->op) {
case CMD_VALUE_INPUT: {
fprintf(stderr, "%p -> LIT(%d, %f) = %f\n", &current->result, current->dir, inputs[current->index], current->result.value);
@@ -171,7 +179,7 @@ void dump_program(struct drawing *drawing, double inputs[]) {
fprintf(stderr, "%p -> CCT(%p, %p) = (%fx + %fy + %f = 0)\n", &current->result, current->arg1, current->arg2, current->result.line.norm[0], current->result.line.norm[1], current->result.line.C);
}break;
case CMD_POINT_CIRCLE_LINE: {
- fprintf(stderr, "%p -> PCL(%p, %p) = <%f, %f>\n", &current->result, current->arg1, current->arg2, current->result.point.pos[0], current->result.point.pos[1]);
+ fprintf(stderr, "%p -> PCL(%p, %p, %d) = <%f, %f>\n", &current->result, current->arg1, current->arg2, current->root, current->result.point.pos[0], current->result.point.pos[1]);
}break;
case CMD_POINT_CIRCLE_CIRCLE: {
fprintf(stderr, "%p -> PCC(%p, %p) = <%f, %f>\n", &current->result, current->arg1, current->arg2, current->result.point.pos[0], current->result.point.pos[1]);
@@ -201,7 +209,11 @@ void dump_program(struct drawing *drawing, double inputs[]) {
void place_points(struct drawing *drawing, double inputs[]) {
struct command *outer_object = drawing->root;
+ uint32_t i = 0;
for(struct command *current = drawing->root; current != NULL; current = current->next) {
+ // if(i++ > 36) break;
+ current->placed = true;
+
switch(current->op) {
case CMD_VALUE_INPUT: {
assert(current->result.type == ETYPE_VALUE);
@@ -244,7 +256,7 @@ void place_points(struct drawing *drawing, double inputs[]) {
double value = current->arg3->value;
value = current->root == 0 ? value : -value;
glm_vec2_rotate(current->arg2->line.norm, value, current->result.line.norm);
- // printf("%f %f\n", current->result.line.norm[0], current->result.line.norm[1]);
+ fprintf(stderr, "%f %f\n", current->result.line.norm[0], current->result.line.norm[1]);
vec2 offset = {-current->arg1->point.pos[0], -current->arg1->point.pos[1]};
current->result.line.C = glm_vec2_dot(current->result.line.norm, offset);
@@ -366,16 +378,14 @@ void place_points(struct drawing *drawing, double inputs[]) {
double dot = glm_vec2_dot(current->arg2->line.norm, current->arg1->point.pos);
current->result.value = (dot + current->arg2->line.C) / glm_vec2_norm(current->arg2->line.norm);
- fprintf(stderr, "Measured Distance %f\n", current->result.value);
}break;
case CMD_MEASURE_LINE_LINE_ANGLE: {
assert(current->arg1->type == ETYPE_LINE);
assert(current->arg2->type == ETYPE_LINE);
assert(current->result.type == ETYPE_VALUE);
- double theta = atan2(current->arg1->line.norm[1], current->arg1->line.norm[0]) - atan2(current->arg2->line.norm[1], current->arg2->line.norm[0]);
+ double theta = atan2(current->arg2->line.norm[1], current->arg2->line.norm[0]) - atan2(current->arg1->line.norm[1], current->arg1->line.norm[0]);
current->result.value = theta;
- fprintf(stderr, "Measured Angle %f\n", current->result.value);
}break;
}
// printf("%fx + %fy + %f = 0\n", cmd[2].line.norm[0], cmd[2].line.norm[1], cmd[2].line.C);
diff --git a/src/debug.c b/src/debug.c
index 97f0b3c..0a9767a 100644
--- a/src/debug.c
+++ b/src/debug.c
@@ -1,4 +1,6 @@
#include "cad/debug.h"
+#include "cglm/types.h"
+#include "cglm/cglm.h"
static const char *component_type_name[] = {
[COM_POINT] = "point",
diff --git a/src/main.c b/src/main.c
index 10cbbfc..60ca295 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,17 +1,6 @@
#include "cad.h"
#include "cad/debug.h"
-#define CIMGUI_DEFINE_ENUMS_AND_STRUCTS
-#include "cimgui/cimgui.h"
-#include "cimgui/cimgui_impl.h"
-#include <SDL2/SDL.h>
-
-#include <GL/gl.h>
-#include <GL/glu.h>
-
-#define igGetIO igGetIO_Nil
-SDL_Window *window = NULL;
-
struct smooth_line {
struct component l1;
struct component l2;
@@ -157,12 +146,13 @@ void draw_from_constraints(struct constraints *c, struct topology *t, struct can
draw_topology(cv, t);
draw_constraints(cv, c);
+ draw_elements(cv, &drawing);
end_drawing(cv);
free_drawing(&drawing);
}
-int main2(int argc, char *argv[]) {
+int main(int argc, char *argv[]) {
struct constraints constraints = {};
struct topology topo = {};
@@ -293,166 +283,3 @@ int main2(int argc, char *argv[]) {
free_topology(&topo);
return 0;
}
-
-int main(int argc, char* argv[]) {
-
- if (SDL_Init(SDL_INIT_VIDEO) < 0) {
- SDL_Log("failed to init: %s", SDL_GetError());
- return -1;
- }
-
- // GL 3.0 + GLSL 130
- const char* glsl_version = "#version 130";
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, 0);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
- SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
-
- // and prepare OpenGL stuff
- SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
- SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
- SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8);
- SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
- SDL_DisplayMode current;
- SDL_GetCurrentDisplayMode(0, &current);
- float main_scale = ImGui_ImplSDL2_GetContentScaleForDisplay(0);
- SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI);
- window = SDL_CreateWindow("Dear ImGui SDL2+OpenGL3 example", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, (int)(1280 * main_scale), (int)(720 * main_scale), window_flags);
-
- if (window == NULL) {
- SDL_Log("Failed to create window: %s", SDL_GetError());
- return -1;
- }
-
- SDL_GLContext gl_context = SDL_GL_CreateContext(window);
- SDL_GL_SetSwapInterval(1); // enable vsync
-
-
- // check opengl version sdl uses
- SDL_Log("opengl version: %s", (char*)glGetString(GL_VERSION));
-
- // setup imgui
- igCreateContext(NULL);
-
- //set docking
- ImGuiIO* ioptr = igGetIO();
- ioptr->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
- ioptr->ConfigFlags |= ImGuiConfigFlags_DockingEnable;
-
- // Setup scaling
- ImGuiStyle* style = igGetStyle();
- ImGuiStyle_ScaleAllSizes(style, main_scale); // Bake a fixed style scale. (until we have a solution for dynamic style scaling, changing this requires resetting Style + calling this again)
- style->FontScaleDpi = main_scale; // Set initial font scale. (using io.ConfigDpiScaleFonts=true makes this unnecessary. We leave both here for documentation purpose)
- ioptr->ConfigDpiScaleFonts = true; // [Experimental] Automatically overwrite style.FontScaleDpi in Begin() when Monitor DPI changes. This will scale fonts but _NOT_ scale sizes/padding for now.
- ioptr->ConfigDpiScaleViewports = true; // [Experimental] Scale Dear ImGui and Platform Windows when Monitor DPI changes.
-
-
- ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
- ImGui_ImplOpenGL3_Init(glsl_version);
-
- igStyleColorsDark(NULL);
- //ImFontAtlas_AddFontDefault(io.Fonts, NULL);
-
-
- bool showDemoWindow = true;
- bool showAnotherWindow = false;
- ImVec4 clearColor;
- clearColor.x = 0.45f;
- clearColor.y = 0.55f;
- clearColor.z = 0.60f;
- clearColor.w = 1.00f;
-
- bool quit = false;
- while (!quit)
- {
- SDL_Event e;
-
- // we need to call SDL_PollEvent to let window rendered, otherwise
- // no window will be shown
- while (SDL_PollEvent(&e) != 0)
- {
- ImGui_ImplSDL2_ProcessEvent(&e);
- if (e.type == SDL_QUIT)
- quit = true;
- if (e.type == SDL_WINDOWEVENT && e.window.event == SDL_WINDOWEVENT_CLOSE && e.window.windowID == SDL_GetWindowID(window))
- quit = true;
- }
-
- // start imgui frame
- ImGui_ImplOpenGL3_NewFrame();
- ImGui_ImplSDL2_NewFrame();
- igNewFrame();
-
- if (showDemoWindow)
- igShowDemoWindow(&showDemoWindow);
-
- // show a simple window that we created ourselves.
- {
- static float f = 0.0f;
- static int counter = 0;
-
- igBegin("Hello, world!", NULL, 0);
- igText("This is some useful text");
- igCheckbox("Demo window", &showDemoWindow);
- igCheckbox("Another window", &showAnotherWindow);
-
- igSliderFloat("Float", &f, 0.0f, 1.0f, "%.3f", 0);
- igColorEdit3("clear color", (float*)&clearColor, 0);
-
- ImVec2 buttonSize;
- buttonSize.x = 0;
- buttonSize.y = 0;
- if (igButton("Button", buttonSize))
- counter++;
- igSameLine(0.0f, -1.0f);
- igText("counter = %d", counter);
-
- igText("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / igGetIO()->Framerate, igGetIO()->Framerate);
- igEnd();
- }
-
- if (showAnotherWindow)
- {
- igBegin("imgui Another Window", &showAnotherWindow, 0);
- igText("Hello from imgui");
- ImVec2 buttonSize;
- buttonSize.x = 0; buttonSize.y = 0;
- if (igButton("Close me", buttonSize))
- {
- showAnotherWindow = false;
- }
- igEnd();
- }
-
- // render
- igRender();
- SDL_GL_MakeCurrent(window, gl_context);
- glViewport(0, 0, (int)ioptr->DisplaySize.x, (int)ioptr->DisplaySize.y);
- glClearColor(clearColor.x, clearColor.y, clearColor.z, clearColor.w);
- glClear(GL_COLOR_BUFFER_BIT);
- ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData());
- if (ioptr->ConfigFlags & ImGuiConfigFlags_ViewportsEnable) {
- SDL_Window* backup_current_window = SDL_GL_GetCurrentWindow();
- SDL_GLContext backup_current_context = SDL_GL_GetCurrentContext();
- igUpdatePlatformWindows();
- igRenderPlatformWindowsDefault(NULL,NULL);
- SDL_GL_MakeCurrent(backup_current_window, backup_current_context);
- }
- SDL_GL_SwapWindow(window);
- }
-
- // clean up
- ImGui_ImplOpenGL3_Shutdown();
- ImGui_ImplSDL2_Shutdown();
- igDestroyContext(NULL);
-
- SDL_GL_DeleteContext(gl_context);
- if (window != NULL)
- {
- SDL_DestroyWindow(window);
- window = NULL;
- }
- SDL_Quit();
-
- return 0;
-}
diff --git a/src/solve.c b/src/solve.c
index 0eab611..67a7bff 100644
--- a/src/solve.c
+++ b/src/solve.c
@@ -143,6 +143,7 @@ static bool fix_first(struct constraint *constraints, size_t constraints_num, si
if(constraints[i].c1->ein != NULL) continue;
if(constraints[i].c2->ein != NULL) continue;
+ fprintf(stderr, "Fix %ld\n", i);
*c = i;
return true;
}
@@ -553,7 +554,7 @@ static size_t build_triangles(struct constraints *constraints_in, struct compone
if(possibly_angle_c == NULL) continue;
- fprintf(stderr, "Assembly %p and %p, %d %d %s %s\n", ein_a, ein_b, f1_c, f2_c, constraint_type_name[not_angle_c->type], constraint_type_name[possibly_angle_c->type]);
+ fprintf(stderr, "%ld %ld Assembly %p and %p, %d %d %s %s\n", i, j, ein_a, ein_b, f1_c, f2_c, constraint_type_name[not_angle_c->type], constraint_type_name[possibly_angle_c->type]);
// We've fixed the subcomponents, so we have to fix
// the whole thing
@@ -640,6 +641,49 @@ nomatch:
return steps_i;
}
+static void point_from_line_and_distance(struct drawing *drawing, struct constraint *constraints, size_t c1, size_t c2, struct element *line, struct element *point, int root, struct element **result) {
+ assert(line->type == ETYPE_LINE);
+ assert(point->type == ETYPE_POINT);
+
+ struct element *d1 = insert_cmd(drawing, (struct command){
+ .op = CMD_VALUE_INPUT,
+ .index = c1,
+ .dir = constraints[c1].forward,
+ .result.type = ETYPE_VALUE,
+ });
+ struct element *d2 = insert_cmd(drawing, (struct command){
+ .op = CMD_VALUE_INPUT,
+ .index = c2,
+ .dir = constraints[c2].forward,
+ .result.type = ETYPE_VALUE,
+ });
+
+ struct element *l = insert_cmd(drawing, (struct command){
+ .op = CMD_LINE_LINE_DISTANCE_PARALLEL,
+ .hidden = false,
+ .result.type = ETYPE_LINE,
+ .arg1 = line,
+ .arg2 = d1,
+ });
+
+ struct element *c = insert_cmd(drawing, (struct command){
+ .op = CMD_CIRCLE_CENTER_RADIUS,
+ .hidden = false,
+ .result.type = ETYPE_CIRCLE,
+ .arg1 = point,
+ .arg2 = d2,
+ });
+
+ *result = insert_cmd(drawing, (struct command){
+ .op = CMD_POINT_CIRCLE_LINE,
+ .hidden = false,
+ .root = root,
+ .result.type = ETYPE_POINT,
+ .arg1 = c,
+ .arg2 = l,
+ });
+}
+
static void draw_point_from_2_distance(struct drawing *drawing, struct constraint *constraints, size_t i, size_t j, struct component *local_i, struct component *local_j, struct element **e, bool shown) {
struct element *d1 = insert_cmd(drawing, (struct command){
.op = CMD_VALUE_INPUT,
@@ -722,10 +766,33 @@ static void draw_for_subassembly(struct constraint *constraints, size_t fix, str
// @HACK Let's only solve for an explicit angle for now
assert(constraints[step->j].type == CT_LINE_LINE_ANGLE);
- // The point we share with the subassembly
struct element *p = NULL;
- draw_point_from_2_distance(drawing, constraints, step->i, step->k, local_i, local_k, &p, false);
- assert(p != NULL);
+ if(constraints[step->i].type == CT_POINT_POINT_DISTANCE
+ && local_i->type == COM_POINT
+ && constraints[step->k].type == CT_POINT_POINT_DISTANCE
+ && local_k->type == COM_POINT) {
+
+ draw_point_from_2_distance(drawing, constraints, step->i, step->k, local_i, local_k, &p, false);
+ assert(p != NULL);
+ } else if(constraints[step->i].type == CT_POINT_LINE_DISTANCE
+ && local_i->type == COM_LINE
+ && constraints[step->k].type == CT_POINT_POINT_DISTANCE
+ && local_k->type == COM_POINT) {
+ assert(oppo_i->type == COM_POINT);
+
+ point_from_line_and_distance(drawing, constraints, step->i, step->k, local_i->e, local_k->e, constraints[step->k].c2 == local_k, &p);
+ } else if(constraints[step->i].type == CT_POINT_POINT_DISTANCE
+ && local_i->type == COM_POINT
+ && constraints[step->k].type == CT_POINT_LINE_DISTANCE
+ && local_k->type == COM_LINE) {
+ assert(oppo_i->type == COM_POINT);
+
+ point_from_line_and_distance(drawing, constraints, step->k, step->i, local_k->e, local_i->e, constraints[step->i].c2 == local_i, &p);
+ } else {
+ abort();
+ }
+
+ // The point we share with the subassembly
// The line that matches the angle
struct element *theta = insert_cmd(drawing, (struct command){
@@ -755,49 +822,6 @@ static void draw_for_subassembly(struct constraint *constraints, size_t fix, str
});
}
-void point_from_line_and_distance(struct drawing *drawing, struct constraint *constraints, size_t c1, size_t c2, struct element *line, struct element *point, int root, struct element **result) {
- assert(line->type == ETYPE_LINE);
- assert(point->type == ETYPE_POINT);
-
- struct element *d1 = insert_cmd(drawing, (struct command){
- .op = CMD_VALUE_INPUT,
- .index = c1,
- .dir = constraints[c1].forward,
- .result.type = ETYPE_VALUE,
- });
- struct element *d2 = insert_cmd(drawing, (struct command){
- .op = CMD_VALUE_INPUT,
- .index = c2,
- .dir = constraints[c2].forward,
- .result.type = ETYPE_VALUE,
- });
-
- struct element *l = insert_cmd(drawing, (struct command){
- .op = CMD_LINE_LINE_DISTANCE_PARALLEL,
- .hidden = false,
- .result.type = ETYPE_LINE,
- .arg1 = line,
- .arg2 = d1,
- });
-
- struct element *c = insert_cmd(drawing, (struct command){
- .op = CMD_CIRCLE_CENTER_RADIUS,
- .hidden = false,
- .result.type = ETYPE_CIRCLE,
- .arg1 = point,
- .arg2 = d2,
- });
-
- *result = insert_cmd(drawing, (struct command){
- .op = CMD_POINT_CIRCLE_LINE,
- .hidden = false,
- .root = root,
- .result.type = ETYPE_POINT,
- .arg1 = c,
- .arg2 = l,
- });
-}
-
#define expand_constraint(NAME, IDX) \
struct constraint *NAME = &constraints[IDX]; \
struct component *NAME##_local; \
@@ -853,7 +877,7 @@ static void draw_for_double_subassembly(struct constraint *constraints, size_t f
// The basic idea here is to create some new points for ax_oppo and bx_oppo
// which we can then use to place a circle or line
struct element *ax_oppo_locally = {};
- point_from_line_and_distance(drawing, constraints, step->j, step->i, a2_local->e, a1_local->e, constraints[step->j].c2 == a2_local, &ax_oppo_locally);
+ point_from_line_and_distance(drawing, constraints, step->j, step->i, a2_local->e, a1_local->e, constraints[step->j].c2 != a2_local, &ax_oppo_locally);
struct element *bx_oppo_locally = {};
build_angle_point_line2(drawing, constraints, step->x, step->k, b2_local->e, b1_local->e, true, &bx_oppo_locally);
@@ -1175,7 +1199,7 @@ static void draw_solution(struct constraint *constraints, size_t fix, struct sol
// @COPYPASTA: Taken from above but with params swapped
assert(oppo_i->type == COM_POINT);
- point_from_line_and_distance(drawing, constraints, step->j, step->i, local_j->e, local_i->e, constraints[step->j].c2 == local_i, &oppo_i->e);
+ point_from_line_and_distance(drawing, constraints, step->j, step->i, local_j->e, local_i->e, constraints[step->i].c2 == local_i, &oppo_i->e);
} else {
CRASH("Unknown constraint combination %s and %s\n", constraint_type_name[constraints[step->i].type], constraint_type_name[constraints[step->j].type]);
}
@@ -1185,13 +1209,20 @@ static void draw_solution(struct constraint *constraints, size_t fix, struct sol
assembly->last_command = drawing->tail;
}
-int unt64_t_compar(const void *a, const void *b) {
+int uint64_t_compar(const void *a, const void *b) {
uint64_t x = *(const uint64_t*)a;
uint64_t y = *(const uint64_t*)b;
return (x > y) - (x < y);
}
+int id_ptr_compar(const void *a, const void *b) {
+ const struct component *x = *(const struct component**)a;
+ const struct component *y = *(const struct component**)b;
+
+ return (x->id > y->id) - (x->id < y->id);
+}
+
bool solve_constraints(struct constraints *constraints, struct drawing *drawing, struct subassembly *assemblies, size_t *assemblies_num) {
*assemblies_num = 0;
// Replace all the aliased points with the point they point to
@@ -1210,11 +1241,13 @@ bool solve_constraints(struct constraints *constraints, struct drawing *drawing,
size_t component_num = 0;
for(size_t i = 0; i < constraints->length; i++) {
+ constraints->elements[i].c1->id = constraints->elements[i].c1->id != 0 ? constraints->elements[i].c1->id : i+1;
components[component_num++] = constraints->elements[i].c1;
+ constraints->elements[i].c2->id = constraints->elements[i].c2->id != 0 ? constraints->elements[i].c2->id : i+1;
components[component_num++] = constraints->elements[i].c2;
}
- qsort(components, component_num, sizeof(struct component*), unt64_t_compar);
+ qsort(components, component_num, sizeof(struct component*), uint64_t_compar);
size_t dest_num = 1;
for(size_t i = 1; i < component_num; i++) {
@@ -1222,6 +1255,8 @@ bool solve_constraints(struct constraints *constraints, struct drawing *drawing,
components[dest_num++] = components[i];
}
+ qsort(components, dest_num, sizeof(struct component*), id_ptr_compar);
+
// Pick some point point distance constraint as the base
size_t fix;
while(fix_first(constraints->elements, constraints->length, &fix)) {
@@ -1232,12 +1267,12 @@ bool solve_constraints(struct constraints *constraints, struct drawing *drawing,
assemblies[*assemblies_num].steps_num = build_triangles(constraints, components, dest_num, fix, *assemblies_num+1, &assemblies[*assemblies_num]);
assemblies[*assemblies_num].fix = fix;
- // printf("Assembly %ld\n", *assemblies_num);
+ // printf("Assembly %ld %ld\n", *assemblies_num, fix);
// for(size_t i = 0; i < assemblies[*assemblies_num].articulation_num; i++) {
// printf(" Articulation %p\n", assemblies[*assemblies_num].articulation[i]);
// }
- // printf("Solved in %ld steps\n", steps_num);
+ // printf("Solved in %ld steps\n", assemblies[*assemblies_num].steps_num);
draw_solution(constraints->elements, fix, assemblies[*assemblies_num].steps, assemblies[*assemblies_num].steps_num, drawing, &assemblies[*assemblies_num]);
for(size_t i = 0; i < assemblies[*assemblies_num].articulation_num; i++) {
diff --git a/src/svg.c b/src/svg.c
index 7144482..9cdb5dc 100644
--- a/src/svg.c
+++ b/src/svg.c
@@ -2,8 +2,32 @@
#define SIGNOF(x) ((typeof(x))((x)>0) - ((x)<0))
-void plot_line_between_style(struct canvas *canvas, struct point p1, struct point p2, enum LineStyle style) {
+static void end_coordinate(struct canvas *canvas) {
+ assert(canvas->state == CANVAS_COORDINATE);
+ fprintf(canvas->f, "</g>\n");
+ canvas->state = CANVAS_DRAWING;
+}
+
+static void begin_coordinate(struct canvas *canvas) {
+ if(canvas->state == CANVAS_COORDINATE) {
+ end_coordinate(canvas);
+ }
+
assert(canvas->state == CANVAS_DRAWING);
+ fprintf(canvas->f, "<g transform=\"translate(%lf, %lf)\">\n", canvas->next_offset[0], canvas->next_offset[1]);
+ // canvas->next_offset[0] += 7.5;
+ // canvas->next_offset[1] += 7.5;
+ canvas->state = CANVAS_COORDINATE;
+}
+
+static bool point_valid(struct point p) {
+ return !isnan(p.pos[0]) && !isnan(p.pos[1]);
+}
+
+void plot_line_between_style(struct canvas *canvas, struct point p1, struct point p2, enum LineStyle style) {
+ assert(canvas->state == CANVAS_COORDINATE);
+
+ if(!point_valid(p1) || !point_valid(p2)) return;
char *style_str;
switch(style) {
@@ -29,7 +53,9 @@ void plot_line_between(struct canvas *canvas, struct point p1, struct point p2)
}
void plot_arc_between_style(struct canvas *canvas, struct point c, struct point p1, struct point p2, enum LineStyle style) {
- assert(canvas->state == CANVAS_DRAWING);
+ assert(canvas->state == CANVAS_COORDINATE);
+
+ if(!point_valid(p1) || !point_valid(p2) || !point_valid(c)) return;
char *style_str;
switch(style) {
@@ -72,14 +98,35 @@ void plot_arc_between(struct canvas *canvas, struct point c, struct point p1, st
plot_arc_between_style(canvas, c, p1, p2, LSTYLE_NORMAL);
}
+void plot_point(struct canvas *canvas, struct point p1, enum LineStyle style) {
+ assert(canvas->state == CANVAS_COORDINATE);
+
+ char *style_str = "";
+ switch(style) {
+ case LSTYLE_NORMAL:
+ break;
+ case LSTYLE_CONSTRUCTION:
+ style_str = "fill=\"blue\"";
+ break;
+ case LSTYLE_INDICATOR:
+ break;
+ case LSTYLE_INDICATOR_INLINE:
+ break;
+ }
+
+ fprintf(canvas->f, "<circle %s r=\".3\" cx=\"%f\" cy=\"%f\" />\n", style_str, p1.pos[0], -p1.pos[1]);
+}
+
void plot_text(struct canvas *canvas, struct point p, double angle, char* str) {
- assert(canvas->state == CANVAS_DRAWING);
+ assert(canvas->state == CANVAS_COORDINATE);
+
+ if(!point_valid(p)) return;
fprintf(canvas->f, "<text text-anchor=\"middle\" dominant-baseline=\"central\" transform=\"translate(%f, %f) scale(1, -1) rotate(%f) scale(1, -1)\" font-size=\"0.75\">%s</text>\n", p.pos[0], -p.pos[1], angle * (180.0/M_PI), str);
}
void plot_angle(struct canvas *canvas, struct line l1, struct line l2, double theta, struct point *intersect, struct point *p1, struct point *p2) {
- assert(canvas->state == CANVAS_DRAWING);
+ assert(canvas->state == CANVAS_COORDINATE);
line_line_intersect(l1, l2, intersect);
@@ -148,7 +195,7 @@ void extend_line_to(struct component* c, struct point *p) {
}
static void plot_distance_indicator(struct canvas *canvas, struct point p1, struct point p2, double distance, bool offset) {
- assert(canvas->state == CANVAS_DRAWING);
+ assert(canvas->state == CANVAS_COORDINATE);
vec2 dir;
glm_vec2_sub(p2.pos, p1.pos, dir);
@@ -226,8 +273,101 @@ void line_distance_to_point(struct line l, double d, struct point *p) {
glm_vec2_muladds(perp, d, p->pos);
}
+static bool clip_line_box(vec2 norm, float c, vec2 min, vec2 max, vec2 out[2]) {
+ vec2 p;
+ vec2 d = { -norm[1], norm[0] };
+
+ if (fabsf(norm[0]) > fabsf(norm[1])) {
+ p[0] = -c / norm[0];
+ p[1] = 0.0f;
+ } else {
+ p[0] = 0.0f;
+ p[1] = -c / norm[1];
+ }
+
+ float t0 = -INFINITY;
+ float t1 = INFINITY;
+
+ for (int i = 0; i < 2; i++) {
+ if (fabsf(d[i]) < DBL_EPSILON * 1e1) {
+ if (p[i] < min[i] || p[i] > max[i])
+ return false;
+ } else {
+ float lo = (min[i] - p[i]) / d[i];
+ float hi = (max[i] - p[i]) / d[i];
+
+ if (lo > hi) {
+ float tmp = lo;
+ lo = hi;
+ hi = tmp;
+ }
+
+ t0 = fmaxf(t0, lo);
+ t1 = fminf(t1, hi);
+ }
+ }
+
+ if (t0 > t1) return false;
+
+ glm_vec2_copy(p, out[0]);
+ glm_vec2_copy(p, out[1]);
+
+ glm_vec2_muladds(d, t0, out[0]);
+ glm_vec2_muladds(d, t1, out[1]);
+
+ return true;
+}
+
+void draw_elements(struct canvas *canvas, struct drawing *drawing) {
+ assert(canvas->state == CANVAS_DRAWING);
+
+ for(struct command *current = drawing->root; current != NULL && current != drawing->error; current = current->next) {
+ // if(current->hidden) continue;
+ if(!current->placed) continue;
+
+ if(current->op == CMD_ORIGIN) {
+ begin_coordinate(canvas);
+ }
+
+ switch(current->result.type) {
+ case ETYPE_POINT: {
+ plot_point(canvas, current->result.point, LSTYLE_CONSTRUCTION);
+ }break;
+ case ETYPE_CIRCLE: {
+ }break;
+ case ETYPE_LINE: {
+ vec2 p[2] = {};
+ struct line *line = &current->result.line;
+ normalize_line(line);
+ clip_line_box(current->result.line.norm, current->result.line.C, (vec2){-50, -50}, (vec2){50, 50}, p);
+
+ struct point p1 = {};
+ glm_vec2_copy(p[0], p1.pos);
+ struct point p2 = {};
+ glm_vec2_copy(p[1], p2.pos);
+
+ plot_line_between_style(canvas, p1, p2, LSTYLE_CONSTRUCTION);
+
+ {
+ struct point closestPointOnLine = {};
+ glm_vec2_muladds(line->norm, -line->C, closestPointOnLine.pos);
+ struct point p2 = {};
+ glm_vec2_copy(closestPointOnLine.pos, p2.pos);
+ glm_vec2_muladds(line->norm, 2, p2.pos);
+ plot_line_between_style(canvas, closestPointOnLine, p2, LSTYLE_NORMAL);
+ }
+ }break;
+ case ETYPE_VALUE: {
+ }break;
+ }
+ }
+
+ if(canvas->state == CANVAS_COORDINATE) end_coordinate(canvas);
+}
+
void draw_constraints(struct canvas *canvas, struct constraints *constraints) {
assert(canvas->state == CANVAS_DRAWING);
+ begin_coordinate(canvas);
for(size_t i = 0; i < constraints->length; i++) {
struct constraint *constraint = &constraints->elements[i];
@@ -332,10 +472,12 @@ void draw_constraints(struct canvas *canvas, struct constraints *constraints) {
case CT_END: abort();
}
}
+ end_coordinate(canvas);
}
void draw_topology(struct canvas *canvas, struct topology *topo) {
assert(canvas->state == CANVAS_DRAWING);
+ begin_coordinate(canvas);
struct component *head = NULL;
for(size_t i = 0; i < topo->length; i++) {
@@ -363,6 +505,8 @@ void draw_topology(struct canvas *canvas, struct topology *topo) {
abort();
}
}
+
+ end_coordinate(canvas);
}
void begin_drawing(struct canvas *canvas) {
@@ -380,9 +524,13 @@ void begin_drawing(struct canvas *canvas) {
fprintf(canvas->f, "<line x1=\"-1000\" y1=\"0\" x2=\"1000\" y2=\"0\" stroke=\"black\" stroke-width=\"0.1\" stroke-opacity=\"0.4\" />\n");
fprintf(canvas->f, "<line y1=\"-1000\" x1=\"0\" y2=\"1000\" x2=\"0\" stroke=\"black\" stroke-width=\"0.1\" stroke-opacity=\"0.4\" />\n");
canvas->state = CANVAS_DRAWING;
+ glm_vec2_zero(canvas->next_offset);
}
void end_drawing(struct canvas *canvas) {
+ if(canvas->state == CANVAS_COORDINATE) {
+ end_coordinate(canvas);
+ }
assert(canvas->state == CANVAS_DRAWING);
fprintf(canvas->f, "</svg>\n");