Skip to content

Commit fb42f1b

Browse files
iscgarphkahler
authored andcommitted
slvs: support getting the bad constraints in the sketch solving API
This was only available in the system solving API until now, and that made the sketch solving API less usable, even though it's the only API available through the Cython and Emscripten bindings. In this initial implementation there's a redundant allocation and copy of the bad constraint list, but it was done this way in order to make a minimal change that would be the most ergonomic to use from both the C interface as well as the FFI binding interfaces.
1 parent cbe18bb commit fb42f1b

6 files changed

Lines changed: 72 additions & 19 deletions

File tree

exposed/CDemo.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ void ExampleStateful()
4343
// Slvs_Entity c1 = Slvs_AddCircle(g, n, center, radius, wp);
4444

4545
Slvs_Vertical(g, p1, wp, p2);
46-
Slvs_SolveResult res = Slvs_SolveSketch(g, 0);
46+
Slvs_SolveResult res = Slvs_SolveSketch(g, NULL);
4747
printf("res: %i\n", res.result);
4848
printf("dof: %i\n", res.dof);
4949
double p1x = Slvs_GetParamValue(p1.param[0]);

include/slvs.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ typedef struct {
207207
typedef struct {
208208
int result;
209209
int dof;
210-
int bad;
210+
int nbad;
211211
} Slvs_SolveResult;
212212

213213
/* Our base coordinate system has basis vectors
@@ -498,7 +498,14 @@ DLL double Slvs_GetParamValue(uint32_t ph);
498498
DLL void Slvs_SetParamValue(uint32_t ph, double value);
499499

500500
DLL void Slvs_Solve(Slvs_System *sys, uint32_t hg);
501-
DLL Slvs_SolveResult Slvs_SolveSketch(uint32_t hg, int calculateFaileds);
501+
/**
502+
* Setting `bad` to a non NULL pointer enables finding of bad constraints.
503+
* If such constraints are found, `bad` is set to a heap allocated array containing
504+
* the handles of those constraints, while the `nbad` member of the returned
505+
* `Slvs_SolveResult` struct is set to the number of the bad constraints.
506+
* NOTE: the user is responsible for freeing the heap allocated memory using `free()`.
507+
*/
508+
DLL Slvs_SolveResult Slvs_SolveSketch(uint32_t hg, Slvs_hConstraint **bad);
502509
DLL void Slvs_ClearSketch();
503510

504511
#ifdef __cplusplus

js/slvs.d.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,8 @@ export interface Constraint {
2727
export interface SolveResult {
2828
result: number;
2929
dof: number;
30-
bad: number;
30+
nbad: number;
31+
bad: Uint32Array;
3132
}
3233

3334
export interface Vector {

src/slvs/jslib.cpp

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,28 @@
22
#include "slvs.h"
33
#include <emscripten/bind.h>
44

5+
struct JsSolveResult {
6+
int result;
7+
int dof;
8+
size_t nbad;
9+
emscripten::val bad;
10+
};
11+
12+
static JsSolveResult solveSketch(Slvs_hGroup g, bool calculateFaileds) {
13+
JsSolveResult jsResult = {};
14+
Slvs_hConstraint *c = nullptr;
15+
Slvs_SolveResult ret = Slvs_SolveSketch(g, calculateFaileds ? &c : nullptr);
16+
if(c) {
17+
jsResult.bad = emscripten::val::global("Uint32Array").new_(ret.nbad);
18+
jsResult.bad.call<void>("set", emscripten::typed_memory_view(ret.nbad, c));
19+
free(c);
20+
}
21+
jsResult.result = ret.result;
22+
jsResult.dof = ret.dof;
23+
jsResult.nbad = ret.nbad;
24+
return jsResult;
25+
}
26+
527
EMSCRIPTEN_BINDINGS(slvs) {
628
emscripten::constant("C_POINTS_COINCIDENT", SLVS_C_POINTS_COINCIDENT);
729
emscripten::constant("C_PT_PT_DISTANCE", SLVS_C_PT_PT_DISTANCE);
@@ -93,10 +115,11 @@ EMSCRIPTEN_BINDINGS(slvs) {
93115
.field("other", &Slvs_Constraint::other)
94116
.field("other2", &Slvs_Constraint::other2);
95117

96-
emscripten::value_object<Slvs_SolveResult>("Slvs_SolveResult")
97-
.field("result", &Slvs_SolveResult::result)
98-
.field("dof", &Slvs_SolveResult::dof)
99-
.field("bad", &Slvs_SolveResult::bad);
118+
emscripten::value_object<JsSolveResult>("Slvs_SolveResult")
119+
.field("result", &JsSolveResult::result)
120+
.field("dof", &JsSolveResult::dof)
121+
.field("nbad", &JsSolveResult::nbad)
122+
.field("bad", &JsSolveResult::bad);
100123

101124
emscripten::class_<Quaternion>("Quaternion")
102125
.constructor<>()
@@ -178,6 +201,6 @@ EMSCRIPTEN_BINDINGS(slvs) {
178201

179202
emscripten::function("getParamValue", &Slvs_GetParamValue);
180203
emscripten::function("setParamValue", &Slvs_SetParamValue);
181-
emscripten::function("solveSketch", &Slvs_SolveSketch);
204+
emscripten::function("solveSketch", &solveSketch);
182205
emscripten::function("clearSketch", &Slvs_ClearSketch);
183206
}

src/slvs/lib.cpp

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -835,7 +835,7 @@ void Slvs_ClearSketch()
835835
SK.constraint.Clear();
836836
}
837837

838-
Slvs_SolveResult Slvs_SolveSketch(uint32_t shg, int calculateFaileds = 0)
838+
Slvs_SolveResult Slvs_SolveSketch(uint32_t shg, Slvs_hConstraint **bad = nullptr)
839839
{
840840
SYS.Clear();
841841

@@ -916,13 +916,23 @@ Slvs_SolveResult Slvs_SolveSketch(uint32_t shg, int calculateFaileds = 0)
916916
// }
917917

918918
List<hConstraint> badList;
919-
bool andFindBad = calculateFaileds ? true : false;
919+
bool andFindBad = bad != nullptr;
920920

921921
int dof = 0;
922922
SolveResult status = SYS.Solve(&g, &dof, &badList, andFindBad, false, false);
923923
Slvs_SolveResult sr = {};
924924
sr.dof = dof;
925-
sr.bad = badList.n;
925+
sr.nbad = badList.n;
926+
if(bad) {
927+
if(sr.nbad <= 0) {
928+
*bad = nullptr;
929+
} else {
930+
*bad = static_cast<Slvs_hConstraint *>(malloc(sizeof(Slvs_hConstraint) * sr.nbad));
931+
for(int i = 0; i < sr.nbad; ++i) {
932+
(*bad)[i] = badList[i].v;
933+
}
934+
}
935+
}
926936
sr.result = 0;
927937
switch(status) {
928938
case SolveResult::OKAY: {

src/slvs/lib.pyx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
#cython: language_level=3
22
from enum import IntEnum, auto
3+
from libc.stdint cimport uint32_t
4+
from libc.stdlib cimport free
35

46
cdef extern from "slvs.h" nogil:
5-
ctypedef int Slvs_hEntity
6-
ctypedef int Slvs_hGroup
7-
ctypedef int Slvs_hConstraint
8-
ctypedef int Slvs_hParam
7+
ctypedef uint32_t Slvs_hEntity
8+
ctypedef uint32_t Slvs_hGroup
9+
ctypedef uint32_t Slvs_hConstraint
10+
ctypedef uint32_t Slvs_hParam
911

1012
ctypedef struct Slvs_Entity:
1113
Slvs_hEntity h
@@ -35,7 +37,7 @@ cdef extern from "slvs.h" nogil:
3537
ctypedef struct Slvs_SolveResult:
3638
int result
3739
int dof
38-
int bad
40+
int nbad
3941

4042
void Slvs_QuaternionU(double qw, double qx, double qy, double qz,
4143
double *x, double *y, double *z)
@@ -84,7 +86,7 @@ cdef extern from "slvs.h" nogil:
8486
Slvs_Constraint Slvs_LengthDiff(Slvs_hGroup grouph, Slvs_Entity entityA, Slvs_Entity entityB, double value, Slvs_Entity workplane)
8587
Slvs_Constraint Slvs_Dragged(Slvs_hGroup grouph, Slvs_Entity ptA, Slvs_Entity workplane)
8688

87-
Slvs_SolveResult Slvs_SolveSketch(Slvs_hGroup hg, int calculateFaileds) nogil
89+
Slvs_SolveResult Slvs_SolveSketch(Slvs_hGroup hg, Slvs_hConstraint **bad) nogil
8890
double Slvs_GetParamValue(int ph)
8991
double Slvs_SetParamValue(int ph, double value)
9092
void Slvs_ClearSketch()
@@ -363,7 +365,17 @@ class EntityType(IntEnum):
363365
ARC_OF_CIRCLE = _SLVS_E_ARC_OF_CIRCLE
364366

365367
def solve_sketch(grouph: int, calculateFaileds: bool):
366-
return Slvs_SolveSketch(grouph, calculateFaileds)
368+
cdef Slvs_hConstraint *badp = NULL
369+
if not calculateFaileds:
370+
return Slvs_SolveSketch(grouph, NULL)
371+
else:
372+
result = Slvs_SolveSketch(grouph, &badp)
373+
bad = []
374+
if badp != NULL:
375+
for i in range(0, result.nbad):
376+
bad.append(badp[i])
377+
free(badp)
378+
return result, bad
367379

368380
def get_param_value(ph: int):
369381
return Slvs_GetParamValue(ph)

0 commit comments

Comments
 (0)