@@ -743,6 +743,31 @@ private fun androidx.compose.ui.graphics.drawscope.DrawScope.drawGuideKitArrow(
743743 val secondControl = end
744744 .minusScaled(endDirection, controlDistance)
745745 .minusScaled(bendDirection, bendAmount * 0.72f )
746+ val hasTargetArrowHead = config.arrowHead == GuideKitArrowHead .TargetSide ||
747+ config.arrowHead == GuideKitArrowHead .BothSides
748+ val hasInstructionArrowHead = config.arrowHead == GuideKitArrowHead .InstructionBoxSide ||
749+ config.arrowHead == GuideKitArrowHead .BothSides
750+ val targetArrowDirection = end.minus(secondControl).normalized()
751+ val instructionArrowDirection = start.minus(firstControl).normalized()
752+ val arrowHeadNeckDistance = config.arrowHeadNeckDistance(distance)
753+ val bodyStart = if (hasInstructionArrowHead) {
754+ start.minusScaled(instructionArrowDirection, arrowHeadNeckDistance)
755+ } else {
756+ start
757+ }
758+ val bodyEnd = if (hasTargetArrowHead) {
759+ end.minusScaled(targetArrowDirection, arrowHeadNeckDistance)
760+ } else {
761+ end
762+ }
763+ val bodyDistance = bodyStart.distanceTo(bodyEnd)
764+ val bodyControlDistance = (bodyDistance * 0.34f ).coerceIn(70f , 180f )
765+ val bodyFirstControl = bodyStart
766+ .plusScaled(startDirection, bodyControlDistance)
767+ .plusScaled(bendDirection, bendAmount)
768+ val bodySecondControl = bodyEnd
769+ .minusScaled(endDirection, bodyControlDistance)
770+ .minusScaled(bendDirection, bendAmount * 0.72f )
746771 val pathEffect = when (config.lineStyle) {
747772 GuideKitArrowLineStyle .Solid -> null
748773 GuideKitArrowLineStyle .Dashed -> config.dashIntervalsPx
@@ -755,14 +780,14 @@ private fun androidx.compose.ui.graphics.drawscope.DrawScope.drawGuideKitArrow(
755780 }
756781 }
757782 val path = Path ().apply {
758- moveTo(start .x, start .y)
783+ moveTo(bodyStart .x, bodyStart .y)
759784 cubicTo(
760- firstControl .x,
761- firstControl .y,
762- secondControl .x,
763- secondControl .y,
764- end .x,
765- end .y,
785+ bodyFirstControl .x,
786+ bodyFirstControl .y,
787+ bodySecondControl .x,
788+ bodySecondControl .y,
789+ bodyEnd .x,
790+ bodyEnd .y,
766791 )
767792 }
768793
@@ -778,18 +803,18 @@ private fun androidx.compose.ui.graphics.drawscope.DrawScope.drawGuideKitArrow(
778803 )
779804 }
780805
781- if (config.arrowHead == GuideKitArrowHead . TargetSide || config.arrowHead == GuideKitArrowHead . BothSides ) {
806+ if (hasTargetArrowHead ) {
782807 drawArrowHead(
783808 tip = end,
784- previousPoint = secondControl ,
809+ previousPoint = bodyEnd ,
785810 accentColor = color,
786811 config = config,
787812 )
788813 }
789- if (config.arrowHead == GuideKitArrowHead . InstructionBoxSide || config.arrowHead == GuideKitArrowHead . BothSides ) {
814+ if (hasInstructionArrowHead ) {
790815 drawArrowHead(
791816 tip = start,
792- previousPoint = firstControl ,
817+ previousPoint = bodyStart ,
793818 accentColor = color,
794819 config = config,
795820 )
@@ -851,6 +876,16 @@ private fun GuideKitArrowConfig.curveBendAmount(distance: Float): Float {
851876 return (distance * 0.16f + variation).coerceIn(44f , 128f )
852877}
853878
879+ private fun GuideKitArrowConfig.arrowHeadNeckDistance (distance : Float ): Float {
880+ if (arrowHead == GuideKitArrowHead .None ) return 0f
881+
882+ val wingAngle = arrowHeadAngleDegrees.toRadians()
883+ val projectedWingLength = arrowHeadLengthPx * cos(wingAngle)
884+ val widestLineStroke = strokes.maxOfOrNull { it.widthPx } ? : 0f
885+ val naturalNeckDistance = projectedWingLength + (widestLineStroke * 0.35f )
886+ return naturalNeckDistance.coerceAtMost(distance * 0.36f )
887+ }
888+
854889private fun Rect.distanceTo (other : Rect ): Float {
855890 val horizontalGap = when {
856891 right < other.left -> other.left - right
0 commit comments