/* https://github.com/mkraska/meclib/wiki/Feedback-for-Free-Body-Diagrams */
/* 2024 03 04 */
/* https://github.com/mkraska/meclib/wiki/direction%28%29 */
direction(o):=block([%_v, a0, le, r1, r2, a1],
if member(o[1], ["bar", "force", "dashpot", "springt", "springc"]) then return(o[4]-o[3]),
if member(o[1], ["fix1"]) then return([-sin(o[4]*%pi/180), cos(o[4]*%pi/180)]),
if member(o[1], ["fix13"]) then return([cos(o[4]*%pi/180), sin(o[4]*%pi/180)]),
if member(o[1], ["q"]) then (
%_v: o[5]-o[4], le: cabs(%_v[1]+%i*%_v[2]), a0: carg(%_v[1]+%i*%_v[2]),
return([cos(a0+o[8]*pi/180), sin(a0+o[8]*pi/180)])
),
if member(o[1], ["rope"]) then (
/* same math as in meclib */
%_v: o[5]-o[3], le: cabs(%_v[1]+%i*%_v[2]), a0: carg(%_v[1]+%i*%_v[2]),
r1: o[4], r2: o[6], a1: acos((r1-r2)/le),
return(float(%_v+[(r2-r1)*cos(a0-a1), (r2-r1)*sin(a0-a1)]))
)
);
/* https://github.com/mkraska/meclib/wiki/angle%28%29 */
angle(a,b):= block([da,db],
da: direction(a), db: direction(b),
if listp(da) and listp(db) then
return(-carg(da[1]+%i*da[2])+carg(db[1]+%i*db[2]) )
);
/* https://github.com/mkraska/meclib/wiki/moment_of_force%28%29 */
moment_of_force(p, f, fname, rname):=block([vf,vr],
vf: (f[4]-f[3]),
vf: vf/sqrt(vf[1]^2+vf[2]^2)*fname,
vr: (f[3]-p)*rname,
vr[1]*vf[2]-vr[2]*vf[1]
);
/* https://github.com/mkraska/meclib/wiki/parallelp%28%29 */
parallelp(a,b):= block([da,db],
da: direction(a), db: direction(b),
if listp(da) and listp(db) then
return(is (abs(da[1]*db[2]-da[2]*db[1])<0.05) )
);
/* https://github.com/mkraska/meclib/wiki/fb_force_hvxy */
fb_force_hvxy(o,i):=block([dir, name, nl, base, idx],
name: o[i][2], nl: split(name,"_"),
/* base name single character? */
if slength(first(nl)) > 1
then return([sconcat("\\(", name, "\\): Physikalische Größen immer nur mit einem Buchstabe und eventuell Index schreiben, z.B. F_1
." ),false]),
/* is there an index? */
if length(nl) # 2
then return([sconcat("\\(", name, "\\) sollte einen Richtungsindex (x, y, h, v) haben."),false]),
/* are name and index just a single character? */
idx: last(nl),
if slength(idx) > 1
then return([sconcat("\\(", name, "\\): Ein Buchstabe sollte für den Index reichen." ),false]),
/* is the index known? */
if not member(sdowncase(idx), ["h","v","x","y"])
then return([sconcat("\\(", name, "\\): Der Richtungsindex sollte h, v, x oder y sein"),false]),
/* check directions */
dir: direction(o[i]),
if (sdowncase(idx)="h" and abs(dir[2]) > 0.01) then
return([sconcat("\\(", name, "\\) müsste eine horizontale Kraft bezeichnen."),false]),
if (sdowncase(idx)="v" and abs(dir[1]) > 0.01) then
return([sconcat("\\(", name, "\\) müsste eine vertikale Kraft bezeichnen."),false]),
if (sdowncase(idx)="x" and (abs(dir[2]) > 0.01 or dir[1] <0) ) then
return([sconcat("\\(", name, "\\) müsste eine Kraft in positive x-Richtung (nach rechts) bezeichnen."),false]),
if (sdowncase(idx)="y" and (abs(dir[1]) > 0.01 or dir[2] <0) ) then
return([sconcat("\\(", name, "\\) müsste eine Kraft in positive y-Richtung (nach oben) bezeichnen."),false]),
/* Name is ok */
return(["",true])
);
/* https://github.com/mkraska/meclib/wiki/Feedback-for-%22fix1%22 */
fb_fix1(%_o, %_n, %_i, %_description):=block(
[%_txt: sconcat("
",%_description), %_R],
/* Is object i a fixed support */
if ( %_o[%_i][1] # "fix1" ) then return ([sconcat(%_txt, "object ", string(%_i), " is not a fixed support (fix1)"), false]),
/* Is object i de-activated */
if ( %_o[%_i][length(%_o[%_i])] # "hide") then return ([sconcat(%_txt, " ist nicht deaktiviert."), false]),
/* Any reactions found at i? */
if not listp(%_n[%_i]) or %_n[%_i]=[] then return([sconcat(%_txt, "Keine Reaktion gefunden."), false]),
/* Exactly 1 reaction found? */
if (length(%_n[%_i]) > 1) then return( [sconcat(%_txt, "Mehr als eine Reaktion gefunden."), false]),
/* Is the reaction a force? */
if ( %_o[%_n[%_i][1]][1] # "force" ) then return ([sconcat(%_txt, "Die Reaktion muss eine Kraft sein."),false]),
/* Now ready for examination of the reaction */
%_R: %_o[%_n[%_i][1]],
/* Is the force normal to the support? */
if not parallelp(%_R, %_o[%_i]) then return ([sconcat(%_txt, "Die Reaktion \\(", %_R[2], "\\) hat nicht die richtige Richtung."),false]),
/* everything should be ok here */
return([sconcat(%_txt, "Reaktion \\(", %_R[2], "\\) gefunden."),true])
);
fb_fix1_name(%_o, %_n, %_i):=block(
[%_R],
if not listp(%_n[%_i]) then return(["",false]),
%_R: %_o[%_n[%_i][1]],
/* name checking */
if slength(%_R[2]) # 1 then return(["
Ein einzelner Buchstabe sollte für die Bezeichnung der Kraft ausreichen.",false]),
if %_R[2] # %_o[%_i][2] then return(["
Der Name der Reaktionskraft sollte zum Namen des Lagerpunkts passen.", false]),
/* everything should be ok here */
return(["",true])
);
/* https://github.com/mkraska/meclib/wiki/Feedback-for-%22fix12%22 */
fb_fix12(o, n, i, description):=block(
[L1, L2, R1, R2], txt: sconcat("
",description),
/* Is object i an fixed support? */
if not member(o[i][1], ["fix12"])
then return ([sconcat(txt, "object ", string(i), " (", o[i][1], ") is not a fixed support."), false]),
/* Is object i de-activated */
if ( last(o[i]) # "hide") then return ([sconcat(txt, " ist nicht deaktiviert."), false]),
/* Any reactions found at i? */
if not listp(n[i]) or n[i]=[] then return([sconcat(txt, "Keine Reaktion gefunden."), false]),
/* Exactly 2 reaction found? */
if (length(n[i]) > 2) then return( [sconcat(txt, "Mehr als 2 Reaktionen gefunden."), false]),
/* Is the reaction a force? */
if (length(n[i]) < 2) then return( [sconcat(txt, "Weniger als 2 Reaktionen gefunden."), false]),
R1: o[n[i][1]], R2: o[n[i][2]],
/* Is the reaction a force? */
if ( o[n[i][1]][1] # "force" )
then return ([sconcat(txt, "Die Reaktion \\(", R1[2], "\\) muss eine Kraft sein."),false]),
if ( o[n[i][2]][1] # "force" )
then return ([sconcat(txt, "Die Reaktion \\(", R2[2], "\\) muss eine Kraft sein."),false]),
/* Equal names? */
if (R1[2] = R2[2]) then return ([sconcat(txt, "Die Reaktionen müssen verschiedene Namen haben."),false]),
/* Are the reactions non-parallel? */
if parallelp(R1, R2) then return ([sconcat(txt, "Die Reaktionen \\(", R1[2], ",", R2[2], "\\) sind parallel."),false]),
/* everything should be ok here */
return([sconcat(txt, "Reaktionen \\(", R1[2], ",", R2[2], "\\) gefunden. "),true])
);
fb_fix12_name(o, n, i):=block(
[dir, idx, nl, L, R, txt: "", flag:false],
/* do the non-name checks to avoid runtime-errors */
if not member(o[i][1], ["fix12"]) then return (["", false]),
/* Is object i de-activated */
if ( last(o[i]) # "hide") then return (["", false]),
/* Any reactions found at i? */
if not listp(n[i]) or n[i]=[] then return(["", false]),
/* Exactly 2 reaction found? */
if (length(n[i]) > 2) then return( ["", false]),
for ir in n[i] do ( /* loop over the reactions */
R: o[ir],
/* Is the reaction a force? */
if ( R[1] # "force" ) then return,
/* Extract name parts */
nl: split(R[2],"_"),
/* base name single character? */
if slength(nl[1]) > 1 then (flag:true,
txt: sconcat(txt, "
\\(", R[2],
"\\): Physikalische Größen immer nur mit einem Buchstabe und eventuell Index schreiben, z.B. F_1
." ),
return(return)),
/* force name matches support name?*/
if is(nl[1] # o[i][2]) then (flag:true,
txt: sconcat(txt, "
Der Name \\(", R[2], "\\) passt nicht zum Name des Lagerpunkts.")),
/* is there an index? */
if length(nl) # 2 then (flag: true,
txt:sconcat(txt, "
\\(", R[2], "\\) sollte einen Richtungsindex (x, y, h, v) haben.")),
/* is index just a single character? */
idx: last(nl),
if slength(idx) > 1 then (flag:true,
txt: sconcat(txt,"
\\(", R[2], "\\): Ein Buchstabe sollte für den Index reichen." )),
/* is the index known? */
if not member(sdowncase(idx), ["h","v","x","y"]) then (flag:true,
txt: sconcat(txt, "
\\(", R[2], "\\): Der Richtungsindex sollte h, v, x oder y sein")),
/* check directions */
dir: direction(R),
if (sdowncase(idx)="h" and abs(dir[2]) > 0.01) then (flag:true,
txt: sconcat(txt, "
\\(", R[2], "\\) müsste eine horizontale Kraft bezeichnen.")),
if (sdowncase(idx)="v" and abs(dir[1]) > 0.01) then (flag:true,
txt: sconcat(txt, "
\\(", R[2], "\\) müsste eine vertikale Kraft bezeichnen.")),
if (sdowncase(idx)="x" and (abs(dir[2]) > 0.01 or dir[1] <0) ) then (flag:true,
txt: sconcat(txt, "
\\(", R[2], "\\) müsste eine Kraft in positive x-Richtung (nach rechts) bezeichnen.")),
if (sdowncase(idx)="y" and (abs(dir[1]) > 0.01 or dir[2] <0) ) then(flag:true,
txt: sconcat(txt, "
\\(", R[2], "\\) müsste eine Kraft in positive y-Richtung (nach oben) bezeichnen."))
),
if flag then return([txt,false]),
["",true]
);
/* https://github.com/mkraska/meclib/wiki/Feedback-for-%22fix123%22 */
fb_fix123(o, n, i, description):=block(
[sname: o[i][2], txt: sconcat("
",description), lf, lm],
/* Is object i a built-in support? */
if not member(o[i][1], ["fix123"])
then return ([sconcat(txt, "object ", string(i), "(",o[i][1],") is not a built-in support."), false]),
/* Is object i de-activated */
if ( last(o[i]) # "hide") then return ([sconcat(txt, " ist nicht deaktiviert."), false]),
/* Any reactions found at i? */
if not listp(n[i]) or n[i]=[] then return([sconcat(txt, "Keine Reaktion gefunden."), false]),
/* Too few reactions found? */
if (length(n[i]) <3) then return( [sconcat(txt, "Weniger als drei Reaktionen gefunden."), false]),
/* Too many reactions found? */
if (length(n[i]) >3) then return( [sconcat(txt, "Mehr als drei Reaktionen gefunden."), false]),
/* 2 forces and 1 moment?*/
lf: sublist(n[i], lambda ([x], o[x][1]="force")),
lm: sublist(n[i], lambda ([x], o[x][1]="moment")),
if ( length(lf) # 2 or length(lm) #1) then return ([sconcat(txt, "Kräfte: ", length(lf), ", Momente: ", length(lm), " gefunden"),false]),
/* Forces not parallel? */
if (parallelp( o[lf[1]], o[lf[2]] ) ) then return([sconcat(txt, "Die Reaktionen \\(", n[lf[1]], "\\) und \\(", n[lf[2]], "\\) sind parallel."), false]),
/* everything should be ok here */
return([sconcat(txt, "Reaktionskräfte \\(", n[lf[1]], ",", n[lf[2]], "\\) und Moment \\(", n[lm[1]], "\\) gefunden."),true])
);
fb_fix123_name(o, n, i):=block(
[sname: o[i][2], txt: "", ir, fb_required, ntxt, nok],
/* make sure that there is at least one reaction */
if not listp(n[i]) or n[i]=[] then return(["", false]),
/*iterate over reactions*/
fb_required: false,
for ir in n[i] do (
/* feedback for forces */
if o[ir][1]="force" then (
if (sname # first(charlist( o[ir][2] )) ) then (
txt: sconcat(txt, "
Der Name \\(", n[ir], "\\) passt nicht zum Name des Lagerpunktes."),
fb_required: true),
[ntxt,nok]: fb_force_hvxy(o, ir),
if not nok then (
txt: sconcat(txt, "
", ntxt),
fb_required: true)
),
/* Feedback for moments */
if o[ir][1]="moment" then (
if (sname # last(charlist( o[ir][2] )) ) then (
txt: sconcat(txt, "
Der Name \\(", n[ir], "\\) passt nicht zum Name des Lagerpunktes."),
fb_required: true),
if (first(charlist( o[ir][2] )) # "M" ) then (
txt: sconcat(txt, "
Der Name \\(", n[ir], "\\) passt nicht zu einem Moment."),
fb_required: true)
)
),
if fb_required then return([txt, false]),
["",true]
);
/* https://github.com/mkraska/meclib/wiki/Feedback-for-%22fix13%22 */
fb_fix13(o, n, i, description):=block(
[sname: o[i][2], txt: sconcat("
",description), lf, lm],
/* Is object a frictionless support? */
if not member(o[i][1], ["fix13"])
then return ([sconcat(txt, "object ", string(i), "(",o[i][1],") is not a frictionless support."), false]),
/* Is object i de-activated */
if ( last(o[i]) # "hide") then return ([sconcat(txt, " ist nicht deaktiviert."), false]),
/* Any reactions found at i? */
if not listp(n[i]) or n[i]=[] then return([sconcat(txt, "Keine Reaktion gefunden."), false]),
/* Too few reactions found? */
if (length(n[i]) <2) then return( [sconcat(txt, "Weniger als zwei Reaktionen gefunden."), false]),
/* Too many reactions found? */
if (length(n[i]) >2) then return( [sconcat(txt, "Mehr als zwei Reaktionen gefunden."), false]),
/* 1 force and 1 moment?*/
lf: sublist(n[i], lambda ([x], o[x][1]="force")),
lm: sublist(n[i], lambda ([x], o[x][1]="moment")),
if ( length(lf) # 1 or length(lm) #1) then return ([sconcat(txt, "Kräfte: ", length(lf), ", Momente: ", length(lm), " gefunden"),false]),
/* Forces in correct direction? */
if (not parallelp( o[i], o[lf[1]] ) ) then return([sconcat(txt, "Die Reaktion \\(", n[lf[1]], "\\) hat nicht die richtige Richtung."), false]),
/* everything should be ok here */
return([sconcat(txt, "Reaktionskraft \\(", n[lf[1]], "\\) und Moment \\(", n[lm[1]], "\\) gefunden."),true])
);
fb_fix13_names(o, n, i):=block(
[sname: o[i][2], txt: "", ir, fb_required, ntxt, nok],
/* make sure that there is at least one reaction */
if not listp(n[i]) or n[i]=[] then return(["", false]),
/*iterate over reactions*/
fb_required: false,
for ir in n[i] do (
/* feedback for forces */
if o[ir][1]="force" then (
if slength(o[ir][2]) # 1 then (
txt: sconcat( txt, "
\\(", n[ir], "\\) Ein einzelner Buchstabe sollte für die Bezeichnung der Kraft ausreichen"),
fb_required: true),
if (sname # o[ir][2] ) then (
txt: sconcat(txt, "
Der Name \\(", n[ir], "\\) passt nicht zum Name des Lagerpunktes."),
fb_required: true),
[ntxt,nok]: fb_force_hvxy(o, ir),
if not nok then (
txt: sconcat(txt, "
", ntxt),
fb_required: true)
),
if o[ir][1]="moment" then (
if (sname # last(charlist( o[ir][2] )) ) then (
txt: sconcat(txt, "
Der Name \\(", n[ir], "\\) passt nicht zum Name des Lagerpunktes."),
fb_required: true),
if (first(charlist( o[ir][2] )) # "M" ) then (
txt: sconcat(txt, "
Der Name \\(", n[ir], "\\) passt nicht zu einem Moment."),
fb_required: true)
)
),
if fb_required then return([txt, false]),
["",true]
);
/* https://github.com/mkraska/meclib/wiki/Feedback-for-unidirectional-supports */
fb_unidir(o, n, i, description):=block(
[txt, R], txt: description,
/* Is object i an unidirectional support? */
if not member(o[i][1], ["bar", "dashpot", "springt", "springc", "fix1", "rope"])
then return ([sconcat(txt, "object ", string(i), " (",o[i][1],") is not an unidirectional support."), false]),
/* Is object i de-activated */
if ( last(o[i]) # "hide") then return ([sconcat(txt, "Nicht deaktiviert."), false]),
/* Any reactions found at i? */
if not listp(n[i]) or n[i]=[] then return([sconcat(txt, "Keine Reaktion gefunden."), false]),
/* Exactly 1 reaction found? */
if (length(n[i]) > 1) then return( [sconcat(txt, "Mehr als eine Reaktion gefunden."), false]),
/* Is the reaction a force? */
if ( o[n[i][1]][1] # "force" ) then return ([sconcat(txt, "Die Reaktion muss eine Kraft sein."),false]),
R: o[n[i][1]],
/* Is the force normal to the support? */
if not parallelp(R, o[i]) then return ([castext_concat(txt, castext("Die Reaktion \\({@n[n[i][1]]@}\\) hat nicht die richtige Richtung.") ),false]),
/* everything should be ok here */
return([castext_concat(txt, castext("Reaktion \\({@n[n[i][1]]@}\\) gefunden.") ),true])
);
/* https://github.com/mkraska/meclib/wiki/Feedback-for-line-loads */
fb_q(o, n, i, description,q1,q2,le):=block(
[varcheck, txt: description, %_v, ir, ir1, ir2, %_R, mag, a0, xref, Rref, lm],
/* Is object a line load? */
if not member(o[i][1], ["q"])
then return ([sconcat(txt, "object ", string(i), " (",o[i][1],") is not a line load."), false]),
/* Resultant force */
%_v: o[i][5]-o[i][4],
mag: (cabs(%_v[1]+%i*%_v[2]))*le*(q1+q2)/2, a0: carg(%_v[1]+%i*%_v[2]),
xref: (o[i][4]*(2/3*q1+q2/3)+o[i][5]*(q1/3+2/3*q2))/(q1+q2),
Rref: [ "force", mag, xref, xref+[-sin(a0+o[i][8]*pi/180), -cos(a0+o[i][8]*pi/180)] ],
/* Is object i de-activated */
if ( last(o[i]) # "hide") then return ([sconcat(txt, "ist nicht deaktiviert."), false]),
/* Any reactions found at i? */
if not listp(n[i]) or n[i]=[] then return([sconcat(txt, "Keine Resultierende gefunden."), false]),
/* forces only?*/
lm: sublist(n[i], lambda ([x], o[x][1]="moment")),
if ( length(lm) # 0 ) then (
for ir in lm do txt: castext_concat(txt, castext("{@n[ir]@}") ),
return ([castext_concat(txt, " ist keine Kraft." ),false])
),
if (length(n[i]) =1) then ( /* just one reaction */
/* correct direction? */
ir: n[i][1],
if abs(angle(Rref, o[ir]))>0.01 then
return([castext_concat(txt, castext("Die Resultierende {@n[ir]@} hat nicht die richtige Richtung.") ) ,false]),
/* correct set of variables in the expression */
varcheck: fb_vars(n[ir], mag, []),
if varcheck # "" then return( [
castext_concat( castext_concat( txt, castext("Die Resultierende {@n[ir]@} hat nicht den richtigen Betrag. ") ), varcheck),
false]),
/* correct value (comparison requires consistent set of variables) */
if (mag-n[ir])/mag>0.01 then
return([castext_concat(txt, castext("Die Resultierende {@n[ir]@} hat nicht den richtigen Betrag.") ) ,false]),
/* correct position? */
if abs(moment_of_force(xref, o[ir], 1, 1) ) > 0.01 then
return([castext_concat(txt, castext("Die Resultierende {@n[ir]@} geht nicht durch den Schwerpunkt.") ) ,false])
) else ( /* two resultants, should be a trapezoidal load */
/* just two resultants? */
if (length(n[i]) >2) then (
%_R: fb_strip_list(makelist(n[n[i][ir]], ir, 1, length(n[i]) ) ),
return([lreduce(castext_concat, [txt, "Höchstens zwei Resultierende sind sinnvoll. Gefunden wurden mehr:
", %_R ] ), false])
),
if q1 = q2 then return([sconcat(txt, "Bei konstanter Streckenlast sollte eine Resultierende ausreichen.") ,false]),
if q1*q2 =0 then return([sconcat(txt, "Bei einer Dreiecks-Streckenlast sollte eine Resultierende ausreichen.") ,false]),
/* correct direction? */
ir1: n[i][1], ir2: n[i][2],
if abs(angle(Rref, o[ir1]))>0.01 then
return([castext_concat(txt, castext("Die Resultierende {@n[ir1]@} hat nicht die richtige Richtung.") ) ,false]),
if abs(angle(Rref, o[ir2]))>0.01 then
return([castext_concat(txt, castext("Die Resultierende {@n[ir2]@} hat nicht die richtige Richtung.") ) ,false]),
/* correct value */
varcheck: fb_vars(n[ir1], mag, []),
if varcheck # "" then return([ castext_concat( castext_concat( txt, castext("Die Resultierende {@n[ir1]@} kann nicht stimmen. ") ), varcheck) ,false]),
varcheck: fb_vars(n[ir2], mag, []),
if varcheck # "" then return([ castext_concat( castext_concat( txt, castext("Die Resultierende {@n[ir2]@} kann nicht stimmen. ") ), varcheck) ,false]),
if (mag-n[ir1]-n[ir2])/mag>0.01 then
return([castext_concat(txt, castext("Die Summe der Resultierenden {@n[ir1]+n[ir2]@} hat nicht den richtigen Wert. ") ) ,false]),
/* correct position? */
if abs((moment_of_force(xref, o[ir1], n[ir1], 1) + moment_of_force(xref, o[ir2], n[ir2], 1))/mag ) > 0.01 then
return( [castext_concat(txt, castext("Prüfen Sie die Lage der Resultierenden. Der gemeinsame Schwerpunkt entspricht nicht der Streckenlast.
{@n[ir1]@}, {@n[ir2]@}") ) ,false])
),
[sconcat(txt, "Resultierende OK") ,true]
);
/* https://github.com/mkraska/meclib/wiki/fb_bar */
fb_bar(o, n, i, [opt]):=block(
[txt, R, name, testT, test2, opt, L],
/* Extract options */
if length(opt) = 1 then opt: string(opt[1]) else opt: "",
testT: member("T", charlist(opt)),
test2: member("2", charlist(opt)),
/* Is object i a bar? */
if o[i][1] # "bar" then return ([sconcat("object ", string(i), " (",o[i][1],") is not a bar."), false]),
/* Has the object a name? The name is used later to identify associated reactions. */
name: o[i][2],
if name = "" then return ([ sconcat("object #", string(i), " has no name."), false]),
txt: sconcat("Stab ", name, ": "),
/* Is object i de-activated */
if ( last(o[i]) # "hide") then return ([sconcat(txt, "Nicht deaktiviert."), false]),
/* Extract forces with matching name*/
if listp(n[i]) then L: sublist (n[i], lambda ([x], o[x][1]="force" and split(o[x][2],"_")[2] = name )) else L: [],
/* Check number of forces */
if L = [] then return ([ sconcat(txt, "Keine Stabkraft mit passendem Namen (mit Index ", name, ") gefunden.") , false]),
/* Single force required */
if not test2 then (
R: o[L[1]],
/* force parallel to bar? */
if not parallelp(R, o[i]) then return ([castext_concat(txt, castext("{@n[L[1]]@} ist nicht parallel zum Stab.") ),false]),
/* eventually complaining about wrong direction */
if testT and (abs(angle(R, o[i])) > 0.1) then return ([castext_concat(txt, castext("{@n[L[1]]@} ist nicht als Zugkraft definiert.") ), false] ),
return ([castext_concat(txt, castext("{@n[L[1]]@} OK.") ), true] )
)
);
/* https://github.com/mkraska/meclib/wiki/fb_bar_name */
fb_bar_name(%_o, %_n, %_i):=block(
[%_str,%_R,%_nl,%_OK,%_var, %_bl],
/* are the values consistent? */
if length(%_n) # length(%_o) then return(sconcat("length(o)= ",length(%_o), " length(n)=", length(%_n))),
if length(%_n) < %_i then return(sconcat("length(n)= ",length(%_n), " <", %_i)),
/* is the object a bar */
if not member(%_o[%_i][1], ["bar"]) then return ([sconcat("object ", %_i, " is not of type 'bar'"), false]),
/* Is object i de-activated */
if debug then %_str: sconcat("object ", %_i, " is not deactivated (debug message)" ) else %_str: "",
if ( last(%_o[%_i]) # "hide") then return ([%_str, false]),
/* Any reactions found at i? */
if debug then %_str: sconcat("no reaction found at object ", %_i, " (debug message)" ) else %_str: "",
if not listp(%_n[%_i]) or %_n[%_i]=[] then return([%_str, false]),
/* Exactly 1 reaction found? */
if debug then %_str: sconcat("more than one reaction found ", %_n[%_i], " (debug message)" ) else %_str: "",
if (length(%_n[%_i]) > 1) then return( [%_str, false]),
/* now we know it is a single reaction */
%_R: %_o[%_n[%_i][1]],
%_var: %_n[%_n[%_i][1]],
/* Is the reaction a force? */
if debug then %_str: sconcat("Reaction ", %_R[2], " is not a force (debug message)" ) else %_str: "",
if %_R[1] # "force" then return( [%_str, false]),
/* now we have a valid reaction, the remainder is about naming */
%_str: "",
%_OK: true,
/* Extract name parts */
%_nl: split(%_R[2],"_"),
/* base name single character? */
if slength(%_nl[1]) > 1 then [ %_str, %_OK ]:
[ castext( "
{@%_var@}: Physikalische Größen immer nur mit einem Buchstabe und eventuell Index schreiben, z.B. F_1
."
), false ],
/* base name a sensible character? (F-Kraft, N-Normalkraft, S-Stabkraft) */
if not member(charlist(%_nl[1])[1], ["F", "N", "S" ]) then [ %_str, %_OK ]:
[ castext_concat( %_str, castext("
{@%_var@}: Sinnvolle Namen für eine Stabkraft sind \\(F\\) (Kraft), \\(N\\) (Normalkraft) oder \\(S\\) (Stabkraft)") ), false ],
/* label of the bar */
%_bl: %_o[%_i][2],
if %_bl # "" then (
/* the label is not empty */
if length(%_nl) = 2 then /* the reaction should have an index */
if %_bl # %_nl[2] then /* the index and the label don't match */
[ %_str, %_OK ]:
[ castext_concat( %_str, castext("
Der Index {@%_nl[2]@} passt nicht zum Stabname {@%_bl@}.")), false ]
),
[%_str, %_OK]
);
/* https://github.com/mkraska/meclib/wiki/fb_name */
fb_name(n,i,lon):=block([name,txt],
name: none,
if listp(n[i]) and not emptyp(n[i]) then name: n[n[i][1]] else return(["", false]),
if member(name,lon) then return( ["",true]) else
return([castext("\\({@name@} \\) ist kein passender Name für die Lagerreaktion."), false])
);
/* https://github.com/mkraska/meclib/wiki/fb_reactions() */
fb_reactions(%_o, %_f, %_m):=block(
[%_fnum, %_mnum, %_txt, %_OK],
%_fnum: length(sublist_indices (%_o, lambda ([x], x[1]="force" and last(x)="active"))),
%_mnum: length(sublist_indices (%_o, lambda ([x], x[1]="moment" and last(x)="active"))),
if (%_fnum=%_f) and (%_mnum=%_m) then [%_txt, %_OK]: [" Die Zahl der Reaktionen stimmt",true] else (
%_OK: false, %_txt: "",
if %_fnum # %_f then %_txt: sconcat(%_txt, "
Die Zahl der Reaktionskräfte stimmt nicht."),
if %_mnum # %_m then %_txt: sconcat(%_txt, "
Die Zahl der Reaktionsmomente stimmt nicht.")
),
[%_txt,%_OK]
);
/* https://github.com/mkraska/meclib/wiki/fb_system() */
fb_system(%_names, %_sys, %_env, %_hint):=block(
[%_i, %_fb: [" Die Systemgrenzen stimmen. ", true],
%_fbfalse: [sconcat(" Die Systemgrenzen stimmen nicht. ", %_hint), false ] ],
for %_i in %_sys do if (%_names[%_i] # "show") then %_fb: %_fbfalse,
for %_i in %_env do if (%_names[%_i] = "show") then %_fb: %_fbfalse,
return(%_fb)
);
/* https://github.com/mkraska/meclib/wiki/MatchByParallel%28%29 */
matchByParallel(o,n):=block([res, llist],res: [],
/* for all objects */
for i:1 thru length(o) do (
/* if names entry is not a list, copy it to result */
if (not listp(n[i])) then res: endcons(n[i], res) else (
/* either a nondirectional item or parallel to the force */
llist: sublist(n[i],
lambda([x],
member(o[i][1], [ "fix12, fix123", "circle"]) or
parallelp(o[i], o[x] )
)
),
res: endcons(llist, res)
)
),
return(res)
);