@@ -99,6 +99,7 @@ void HangprinterKinematics::Init() noexcept
9999 constexpr float DefaultTorqueConstants[HANGPRINTER_AXES] = { 0 .0F };
100100
101101 ARRAY_INIT (anchors, DefaultAnchors);
102+ anchorMode = HangprinterAnchorMode::LastOnTop;
102103 printRadius = DefaultPrintRadius;
103104 spoolBuildupFactor = DefaultSpoolBuildupFactor;
104105 ARRAY_INIT (spoolRadii, DefaultSpoolRadii);
@@ -229,6 +230,12 @@ bool HangprinterKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const
229230 }
230231 else if (mCode == 666 )
231232 {
233+ // 0=None, 1=last-top, 2=all-top, 3-half-top, etc
234+ uint32_t unsignedAnchorMode = (uint32_t )anchorMode;
235+ gb.TryGetUIValue (' T' , unsignedAnchorMode, seen);
236+ if (unsignedAnchorMode <= (uint32_t )HangprinterAnchorMode::AllOnTop) {
237+ anchorMode = (HangprinterAnchorMode)unsignedAnchorMode;
238+ }
232239 gb.TryGetFValue (' Q' , spoolBuildupFactor, seen);
233240 gb.TryGetFloatArray (' R' , HANGPRINTER_AXES, spoolRadii, seen);
234241 gb.TryGetUIArray (' U' , HANGPRINTER_AXES, mechanicalAdvantage, seen);
@@ -248,7 +255,8 @@ bool HangprinterKinematics::Configure(unsigned int mCode, GCodeBuffer& gb, const
248255 }
249256 else
250257 {
251- reply.printf (" M666 Q%.4f\n " , (double )spoolBuildupFactor);
258+ // TODO T is taken, find a letter that's free
259+ reply.printf (" M666 T%u Q%.4f\n " , (unsigned )anchorMode, (double )spoolBuildupFactor);
252260
253261 reply.lcatf (" R%.2f" , (double )spoolRadii[0 ]);
254262 for (size_t i = 1 ; i < HANGPRINTER_AXES; ++i)
@@ -444,25 +452,51 @@ static bool isSameSide(float const v0[3], float const v1[3], float const v2[3],
444452 return dot0*dot1 > 0 .0F ;
445453}
446454
447- // For each triangle side in a pseudo-pyramid, check if the point is inside the pyramid (Except for the base)
448- // Also check that any point below the line between two exterior anchors (all anchors are exterior except for the last one)
449- // is in the "inside part" all the way down to min_Z, however low it may be.
450- // To further limit the movements in the X and Y axes one can simply set a smaller print radius.
451- bool HangprinterKinematics::IsReachable (float axesCoords[MaxAxes], AxesBitmap axes) const noexcept /* override*/
455+ bool HangprinterKinematics::IsInsidePyramidSides (float const coords[3 ]) const noexcept
452456{
453- float const coords[3 ] = {axesCoords[X_AXIS], axesCoords[Y_AXIS], axesCoords[Z_AXIS]};
454457 bool reachable = true ;
455458
456459 // Check all the planes defined by triangle sides in the pyramid
457460 for (size_t i = 0 ; reachable && i < HANGPRINTER_AXES - 1 ; ++i) {
458461 reachable = reachable && isSameSide (anchors[i], anchors[(i+1 ) % (HANGPRINTER_AXES - 1 )], anchors[HANGPRINTER_AXES - 1 ], anchors[(i+2 ) % (HANGPRINTER_AXES - 1 )], coords);
459462 }
463+ return reachable;
464+ }
465+
466+ bool HangprinterKinematics::IsInsidePrismSides (float const coords[3 ], unsigned const discount_last) const noexcept
467+ {
468+ bool reachable = true ;
460469
461470 // For each side of the base, check the plane formed by side and another point bellow them in z.
462- for (size_t i = 0 ; reachable && i < HANGPRINTER_AXES - 1 ; ++i) {
471+ for (size_t i = 0 ; reachable && i < HANGPRINTER_AXES - discount_last ; ++i) {
463472 float const lower_point[3 ] = {anchors[i][0 ], anchors[i][1 ], anchors[i][2 ] - 1 };
464473 reachable = reachable && isSameSide (anchors[i], anchors[(i+1 ) % (HANGPRINTER_AXES - 1 )], lower_point, anchors[(i+2 ) % (HANGPRINTER_AXES - 1 )], coords);
465474 }
475+ return reachable;
476+ }
477+
478+ // For each triangle side in a pseudo-pyramid, check if the point is inside the pyramid (Except for the base)
479+ // Also check that any point below the line between two exterior anchors (all anchors are exterior except for the last one)
480+ // is in the "inside part" all the way down to min_Z, however low it may be.
481+ // To further limit the movements in the X and Y axes one can simply set a smaller print radius.
482+ bool HangprinterKinematics::IsReachable (float axesCoords[MaxAxes], AxesBitmap axes) const noexcept /* override*/
483+ {
484+ float const coords[3 ] = {axesCoords[X_AXIS], axesCoords[Y_AXIS], axesCoords[Z_AXIS]};
485+ bool reachable = true ;
486+
487+ switch (anchorMode) {
488+ case HangprinterAnchorMode::None:
489+ return true ;
490+
491+ // This reaches a pyramid on top of the lower prism if the bed is below the lower anchors
492+ case HangprinterAnchorMode::LastOnTop:
493+ default :
494+ reachable = IsInsidePyramidSides (coords);
495+ return reachable && IsInsidePrismSides (coords, 1 );
496+
497+ case HangprinterAnchorMode::AllOnTop:
498+ return IsInsidePrismSides (coords, 0 );
499+ };
466500
467501 return reachable;
468502}
@@ -586,7 +620,7 @@ bool HangprinterKinematics::WriteCalibrationParameters(FileStore *f) const noexc
586620 ok = f->Write (scratchString.c_str ());
587621 if (!ok) return false ;
588622
589- scratchString.printf (" M666 Q%.6f " , (double )spoolBuildupFactor);
623+ scratchString.printf (" M666 T%u Q%.6f " , ( unsigned )anchorMode , (double )spoolBuildupFactor);
590624 ok = f->Write (scratchString.c_str ());
591625 if (!ok) return false ;
592626
0 commit comments