/* 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) );