diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..fecd44d --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + groups: + actions: + patterns: ["*"] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c6a8357..0ee4f80 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,6 +43,14 @@ jobs: run: | xcodebuild -project Example/MuscleMapDemoApp.xcodeproj -scheme MuscleMapDemoApp \ -destination 'generic/platform=iOS Simulator' build + - name: Build documentation + run: | + set -o pipefail + xcodebuild docbuild -scheme MuscleMap -destination 'generic/platform=iOS Simulator' | tee docbuild.log + if grep -E '\.md:[0-9]+:[0-9]+: warning' docbuild.log; then + echo "::error::The documentation has warnings" + exit 1 + fi podspec: name: CocoaPods lint diff --git a/.spi.yml b/.spi.yml new file mode 100644 index 0000000..1ab3e8f --- /dev/null +++ b/.spi.yml @@ -0,0 +1,4 @@ +version: 1 +builder: + configs: + - documentation_targets: [MuscleMap] diff --git a/MuscleMap.podspec b/MuscleMap.podspec index 8317994..86bf5ce 100644 --- a/MuscleMap.podspec +++ b/MuscleMap.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "MuscleMap" - s.version = "1.8.0" + s.version = "1.9.0" s.summary = "A SwiftUI SDK for rendering interactive human body muscle maps." s.description = <<-DESC MuscleMap provides a declarative way to display a human body and visualize diff --git a/README.md b/README.md index 5c3a6ae..be5dfca 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,7 @@ Add to your `Package.swift`: ```swift dependencies: [ - .package(url: "https://github.com/melihcolpan/MuscleMap.git", from: "1.8.0") + .package(url: "https://github.com/melihcolpan/MuscleMap.git", from: "1.9.0") ] ``` @@ -56,7 +56,7 @@ Or in Xcode: **File > Add Package Dependencies** and paste the repository URL. Add to your `Podfile`: ```ruby -pod 'MuscleMap', '~> 1.8.0' +pod 'MuscleMap', '~> 1.9.0' ``` Then run `pod install`. @@ -411,7 +411,12 @@ Button("Redo") { if let state = history.redo() { selectedMuscles = state } } ### Muscle Sub-Groups -Sub-groups provide finer control over muscle regions. They inherit the parent muscle's highlight when no specific highlight is set, and take priority in hit testing. +

+ Front Sub-Groups + Back Sub-Groups +

+ +Sub-groups provide finer control over muscle regions. Each one is cut from its parent muscle's artwork: the upper and lower chest, the front deltoid, the upper and lower abs, the serratus slips on the ribs, the top of the quadriceps (hip flexors) and the inner and outer quadriceps heads. They inherit the parent muscle's highlight when no specific highlight is set, and take priority in hit testing. **Always-visible sub-groups** (ankles, adductors, neck) are rendered by default but return their parent muscle on tap — so tapping the ankle area returns `.feet`, tapping the neck returns `.head`, etc. @@ -643,7 +648,9 @@ swift run --package-path Tools/ScreenshotGenerator ScreenshotGenerator Screensho # regenerate the README screenshots ``` -Every push and pull request runs the tests, an iOS build, the demo app build and `pod lib lint` on GitHub Actions. +Every push and pull request runs the tests, an iOS build, the demo app build, the documentation build and `pod lib lint` on GitHub Actions. Dependabot keeps the workflow's actions up to date. + +The API documentation is on the [Swift Package Index](https://swiftpackageindex.com/melihcolpan/MuscleMap/documentation/musclemap). ## License diff --git a/Screenshots/front_subgroups.png b/Screenshots/front_subgroups.png new file mode 100644 index 0000000..563e455 Binary files /dev/null and b/Screenshots/front_subgroups.png differ diff --git a/Sources/MuscleMap/Data/FemaleFrontPaths.swift b/Sources/MuscleMap/Data/FemaleFrontPaths.swift index 9ac98f0..eda36b1 100644 --- a/Sources/MuscleMap/Data/FemaleFrontPaths.swift +++ b/Sources/MuscleMap/Data/FemaleFrontPaths.swift @@ -266,14 +266,18 @@ enum FemaleFrontPaths { BodyPartPathData( slug: .serratus, left: [ - "M226.5 432.2c-2.1-1.3-3.4-3.6-2.9-6.1q1.1-4.8 4.4-7.6c2.2-1.9 5.1-1.6 7.5-.4q3.9 2.1 5.5 6.4c1.1 2.9-.3 6.2-2.8 7.7q-5.3 3.1-11.7-.0z", - "M221.3 449.5c-1.6-1.5-2.6-3.8-1.9-6.1q1.3-4.4 4.9-6.5c2.4-1.5 5.3-.7 7.4 1.0q3.4 2.8 3.8 7.5c.3 3.1-1.4 5.7-4.2 6.7q-5.1 1.8-10-.6z", - "M217.8 468.3c-1.4-1.7-2.0-4.2-1.0-6.4q1.8-3.9 5.5-5.5c2.5-1.1 5.4.1 7.1 2.2q2.8 3.4 2.5 8.1c-.2 3.2-2.1 5.4-5.1 5.9q-4.8 1.1-9-4.3z" + "m 234.32,446.92 c -0.55,-2.95 -0.73,-5.84 -1.94,-8.63 q -4.84,-11.24 -8.61,-21.89 -1.12,-3.17 1.19,-0.73 c 6.09,6.44 10.93,13.52 16.12,20.74 a 1.71,1.68 28.7 0 1 0.33,1.09 q -0.53,11.15 -1.88,22.64 -0.27,2.38 -1.24,0.18 -2.52,-5.75 -3.97,-13.4 z", + "m 242.67,456.5 c 3.65,1.14 7.61,3.78 10.54,6.08 q 2.32,1.82 2.25,4.78 l -0.21,8.13 q -0.04,1.79 -1.45,0.68 -5.7,-4.52 -10.18,-10.21 c -1.95,-2.48 -2.49,-5.57 -2.19,-8.64 a 0.96,0.96 0 0 1 1.24,-0.82 z", + "m 246.6,490.48 c -6.03,-4.05 -7.7,-15.15 -7.34,-21.92 a 0.29,0.29 0 0 1 0.5,-0.19 c 4.79,4.87 9.23,10.01 14.82,13.93 a 1.71,1.7 17.7 0 1 0.72,1.39 l -0.03,11.84 a 0.6,0.6 0 0 1 -0.96,0.47 q -4.04,-3.05 -7.71,-5.52 z", + "m 252.02,456.3 c -3.08,-1.43 -6.59,-6.27 -8.84,-9.51 q -1.03,-1.49 -0.89,-3.31 a 1.39,1.38 -88.2 0 1 1.35,-1.28 q 2.27,-0.04 4.18,0.73 4.36,1.77 9.23,3.14 0.54,0.15 0.58,0.71 0.4,6.12 -1.21,11.67 a 0.35,0.35 0 0 1 -0.56,0.18 q -1.73,-1.34 -3.84,-2.33 z", + "m 259.53,441.27 c -6.09,-0.94 -15.24,-7.47 -17.83,-12.96 a 1.96,1.95 -46.6 0 1 -0.04,-1.54 c 0.68,-1.67 2.51,-1.45 3.82,-0.88 q 8.66,3.77 17.36,6.42 a 0.45,0.45 0 0 1 0.31,0.35 q 0.79,4.96 -2.71,8.32 -0.38,0.37 -0.91,0.29 z" ], right: [ - "M422.8 432.2c2.1-1.3 3.4-3.6 2.9-6.1q-1.1-4.8-4.4-7.6c-2.2-1.9-5.1-1.6-7.5-.4q-3.9 2.1-5.5 6.4c-1.1 2.9.3 6.2 2.8 7.7q5.3 3.1 11.7-.0z", - "M428.0 449.5c1.6-1.5 2.6-3.8 1.9-6.1q-1.3-4.4-4.9-6.5c-2.4-1.5-5.3-.7-7.4 1.0q-3.4 2.8-3.8 7.5c-.3 3.1 1.4 5.7 4.2 6.7q5.1 1.8 10-.6z", - "M432.4 468.3c1.4-1.7 2.0-4.2 1.0-6.4q-1.8-3.9-5.5-5.5c-2.5-1.1-5.4.1-7.1 2.2q-2.8 3.4-2.5 8.1c.2 3.2 2.1 5.4 5.1 5.9q4.8 1.1 9-4.3z" + "m 384.22,445.83 c 4.32,-0.61 8.05,-3.04 12.37,-3.63 q 1.44,-0.19 1.87,1.19 0.52,1.66 -0.54,3.18 c -4.17,5.96 -7.23,9.14 -12.91,11.89 a 0.38,0.38 0 0 1 -0.53,-0.24 q -1.53,-5.28 -1.13,-11.45 a 1.03,1.01 88.3 0 1 0.87,-0.94 z", + "m 393.51,426.7 q 1.7,-0.72 3.57,-1.16 a 1.83,1.83 0 0 1 1.91,0.73 c 0.66,0.94 0.41,2.29 -0.25,3.15 q -6.32,8.23 -15.71,11.52 -3.03,1.06 -4.1,-1.97 -1.12,-3.14 -1.26,-3.53 -1.02,-2.87 1.9,-3.71 6.45,-1.87 13.94,-5.03 z", + "m 398.41,456.38 a 0.8,0.8 0 0 1 1.09,0.63 c 0.86,5.62 -1.96,9.16 -5.73,13.05 q -3.65,3.78 -7.3,6.56 a 0.41,0.41 0 0 1 -0.66,-0.3 q -0.29,-4.61 -0.24,-8.98 0.03,-3.34 2.9,-5.44 4.69,-3.42 9.94,-5.52 z", + "m 401.76,469.17 c 0.19,6.21 -1.1,14.25 -5.22,19.11 -2.62,3.1 -6.7,5.34 -10.07,7.78 q -0.73,0.53 -0.74,-0.38 l -0.07,-12.12 q 0,-0.59 0.46,-0.96 8.07,-6.31 14.53,-13.82 1.06,-1.24 1.11,0.39 z", + "m 417.44,415.21 c -2.14,7.47 -5.47,14.6 -8.52,22.06 q -1.36,3.31 -1.79,6.59 -1.11,8.53 -4.58,16.68 -0.79,1.86 -1.07,-0.14 -1.42,-10.38 -1.9,-22.98 a 1.58,1.57 -28.9 0 1 0.29,-1 q 6.57,-9.46 12.8,-17.21 1.87,-2.32 4.3,-4.31 0.73,-0.59 0.47,0.31 z" ] ), @@ -281,10 +285,10 @@ enum FemaleFrontPaths { BodyPartPathData( slug: .hipFlexors, left: [ - "M273.2 675.5c-3.5-1.9-6.5-5.7-7.3-9.7q-1.3-6.2 1.1-11.9c1.6-3.9 5.3-6.4 9.4-7.1q5.6-.8 10.4 2.5c3.2 2.3 4.7 6.3 4.4 10.2q-.5 6.1-4.8 10.8c-2.8 3.1-7.4 8.0-13.2 5.2z" + "M234 689.9L223.6 656.6L213.5 623.3L213 622.2L212.5 622.1L210.6 629.6L208.7 637.8L207.2 646L205.9 654.8L204.2 671.9L203.7 689.9Z" ], right: [ - "M375.5 675.5c3.5-1.9 6.5-5.7 7.3-9.7q1.3-6.2-1.1-11.9c-1.6-3.9-5.3-6.4-9.4-7.1q-5.6-.8-10.4 2.5c-3.2 2.3-4.7 6.3-4.4 10.2q.5 6.1 4.8 10.8c2.8 3.1 7.4 8.0 13.2 5.2z" + "M437.2 689.9L436.6 671.4L435.8 662.5L434.8 653.6L433.3 644.2L431.5 634.8L428.7 623L428.5 622.5L428.1 622.1L427.6 622.4L417.4 656.2L406.9 689.9Z" ] ), @@ -292,10 +296,10 @@ enum FemaleFrontPaths { BodyPartPathData( slug: .upperChest, left: [ - "M244.5 325.1c4.7-4.3 12.8-7.4 19.4-8.5q11.5-1.6 22.1.5c5.8 1.1 10.1 5.7 12.1 11.3q2.9 8.2 1.6 17.0c-.8 5.6-4.6 9.4-9.8 11.7q-7.7 3.4-16.8 2.2c-6.1-.8-11.9-2.8-16.6-7.1q-7.0-6.3-12.0-27.1z" + "M315.7 365.4L313.5 325.7L312.9 324L311.3 323.2L299.6 320.8L290.8 319.7L283.4 319.2L279.2 319.5L275.1 320.2L269.8 321.6L265.2 323.2L260.9 325L256.7 327.2L252.7 329.7L248.9 332.5L245.8 335.2L242.4 338.5L239.2 342.2L236.6 345.7L230.9 354.9L225.8 365.4Z" ], right: [ - "M404.8 325.1c-4.7-4.3-12.8-7.4-19.4-8.5q-11.5-1.6-22.1.5c-5.8 1.1-10.1 5.7-12.1 11.3q-2.9 8.2-1.6 17.0c.8 5.6 4.6 9.4 9.8 11.7q7.7 3.4 16.8 2.2c6.1-.8 11.9-2.8 16.6-7.1q7.0-6.3 12.0-27.1z" + "M363.4 319.7L360.1 319.3L355.9 319.3L346.7 320L339.6 321.1L333 322.4L329.4 323.2L327.9 324.2L327.5 325.3L325.2 365.4L415.1 365.4L410.7 356.2L405.5 347.5L399.8 340.1L394.4 334.4L387.7 329.3L384.2 327.1L379.9 325L372.1 321.9Z" ] ), @@ -303,10 +307,10 @@ enum FemaleFrontPaths { BodyPartPathData( slug: .lowerChest, left: [ - "M248.2 370.2c2.8-2.5 8.1-4.6 12.0-5.4q8.9-1.6 17.9.3c5.1 1.1 9.2 4.4 11.6 9.2q3.4 6.8 2.2 14.4c-1.0 5.5-5.3 8.9-10.2 10.7q-6.9 2.5-14.6 1.0c-5.2-1.0-9.8-3.5-13.2-7.7q-5.0-6.4-5.7-22.5z" + "M215.3 403.4L216.1 404.3L225.2 409.5L241.1 417.8L254.7 423.8L267.7 428.7L277.4 431.4L286.6 432.8L290.5 433L294.1 432.9L297.7 432.4L300.6 431.6L302.8 430.7L304.9 429.4L308.5 426.3L311.3 423.7L314.2 419.9L315.1 418L315.9 415.4L316.9 408.6L317.2 397.3L316.9 385.5L315.9 368.6L224.5 368.6L221.5 376.9L219 385.6L216.6 395.6Z" ], right: [ - "M401.1 370.2c-2.8-2.5-8.1-4.6-12.0-5.4q-8.9-1.6-17.9.3c-5.1 1.1-9.2 4.4-11.6 9.2q-3.4 6.8-2.2 14.4c1.0 5.5 5.3 8.9 10.2 10.7q6.9 2.5 14.6 1.0c5.2-1.0 9.8-3.5 13.2-7.7q5.0-6.4 5.7-22.5z" + "M325 368.6L323.9 387.4L323.7 398.4L324.1 408.9L325.2 416L326.1 418.5L327 420.4L330.5 424.7L332.9 427L335.6 429L338.3 430.7L340.9 431.8L343.4 432.4L347.5 432.9L351.6 432.9L355.8 432.6L364.8 431.1L374.8 428.3L387.6 423.3L401.4 417L417.7 408.4L425 404.2L425.5 403.8L425.7 403.3L424.1 394.4L421.8 385L419.4 376.8L416.4 368.6Z" ] ), @@ -314,10 +318,10 @@ enum FemaleFrontPaths { BodyPartPathData( slug: .innerQuad, left: [ - "M284.5 755.2c-2.5-1.3-3.7-4.4-3.8-7.4q-.3-11.6 1.9-23.0c1.5-7.5 4.4-14.3 8.4-20.5q5.2-8.0 11.9-14.4c2.2-2.1 5.3-1.1 6.5 1.6q2.9 6.7 3.5 14.2c.7 10.2-.4 20.4-2.9 30.3q-2.5 9.8-7.4 16.7c-3.1 4.4-11.6 5.6-16.1 2.5z" + "m 301.11,919.16 c -0.02,16.26 -1.13,34.39 -10.87,47.81 -1.99,2.73 -6.98,1.8 -10.02,1.14 -1.09,-0.24 -1.35,-1.1 -1.62,-2.04 -3.49,-11.83 -3.03,-24.65 -1.79,-37.03 q 1.41,-14.09 3.35,-26.37 1.6,-10.13 1.54,-18.61 -0.09,-12.6 -1.48,-24.36 c -1.65,-13.85 -3.88,-27.85 -2.4,-41.77 a 0.32,0.32 0 0 1 0.4,-0.28 q 0.4,0.1 0.57,0.48 c 14.17,32.12 22.37,65.88 22.32,101.03 z" ], right: [ - "M364.8 755.2c2.5-1.3 3.7-4.4 3.8-7.4q.3-11.6-1.9-23.0c-1.5-7.5-4.4-14.3-8.4-20.5q-5.2-8.0-11.9-14.4c-2.2-2.1-5.3-1.1-6.5 1.6q-2.9 6.7-3.5 14.2c-.7 10.2.4 20.4 2.9 30.3q2.5 9.8 7.4 16.7c3.1 4.4 11.6 5.6 16.1 2.5z" + "m 350.02,966.12 c -9.24,-14.15 -10.21,-31.4 -10.24,-48.19 -0.07,-33.99 8.51,-69.02 22.57,-100.06 a 0.51,0.49 -76.6 0 1 0.45,-0.29 q 0.28,0 0.31,0.28 c 0.83,7.48 0.62,15.88 -0.25,23.21 -1.72,14.59 -3.74,28.99 -3.61,44.11 q 0.06,8 1.44,16.9 1.82,11.87 3.26,24.93 c 1.49,13.54 2.18,28.24 -1.97,40.04 a 1.57,1.55 2.7 0 1 -1.11,1 q -3.84,0.9 -7.13,0.61 -2.19,-0.19 -3.72,-2.54 z" ] ), @@ -325,10 +329,10 @@ enum FemaleFrontPaths { BodyPartPathData( slug: .outerQuad, left: [ - "M222.4 785.5c-2.9-5.3-4.4-12.0-3.7-18.0q1.1-10.7 5.3-20.7c2.8-6.7 7.1-12.8 12.3-18.0q6.5-6.5 14.6-11.3c2.5-1.5 5.5.2 6.2 3.2q1.6 7.6 1.1 15.6c-.7 11.0-3.5 21.9-7.6 32.0q-4.2 10.1-10.7 18.0c-4.2 5.0-13.2 6.5-17.5-0.8z" + "m 237.75,955.7 c -18.56,-47.89 -33.57,-96.23 -39.84,-146.62 -3.58,-28.72 -3.69,-58.65 1.76,-86.95 q 0.62,-3.18 0.81,0.06 0.5,8.53 1.83,17.04 3.42,21.88 10.35,47.5 6.6,24.41 13.5,49.26 2.72,9.81 5.92,19.09 4.05,11.74 7.55,25.02 1.76,6.7 2.16,12.33 2,28.5 1.14,55.08 c -0.12,3.52 -0.98,6.35 -3.98,8.55 a 0.79,0.79 0 0 1 -1.2,-0.36 z" ], right: [ - "M427.9 785.5c2.9-5.3 4.4-12.0 3.7-18.0q-1.1-10.7-5.3-20.7c-2.8-6.7-7.1-12.8-12.3-18.0q-6.5-6.5-14.6-11.3c-2.5-1.5-5.5.2-6.2 3.2q-1.6 7.6-1.1 15.6c.7 11.0 3.5 21.9 7.6 32.0q4.2 10.1 10.7 18.0c4.2 5.0 13.2 6.5 17.5-0.8z" + "m 441.32,723.15 q 5.4,27.88 3.91,59.43 c -1.5,31.66 -7.16,62.78 -15.56,93.66 q -10.93,40.18 -26.56,79.46 a 0.8,0.8 0 0 1 -1.23,0.34 c -4.09,-3.18 -3.84,-7.55 -3.96,-12.09 q -0.59,-24.2 1.07,-50.23 0.42,-6.4 2.05,-12.77 3.38,-13.22 8.06,-26.98 3.21,-9.44 5.93,-19.09 c 7.96,-28.15 15.34,-53.97 20.99,-81.11 q 3.3,-15.87 4.53,-32.62 0.01,-0.1 0.11,-0.14 l 0.25,-0.09 q 0.11,-0.04 0.12,0.07 0.06,0.98 0.29,2.16 z" ] ), @@ -336,10 +340,14 @@ enum FemaleFrontPaths { BodyPartPathData( slug: .upperAbs, left: [ - "M283.5 425.2c-1.9-1.6-2.9-4.6-2.5-7.4q.7-5.6 3.7-10.4c2.0-3.1 5.3-4.6 8.7-4.8q5.6-.3 10.7 1.9c3.5 1.5 5.3 4.9 4.9 8.7q-.5 6.2-4.4 11.0c-2.5 3.2-6.2 4.4-10.1 3.8q-6.5-.9-11.0-2.8z" + "m 261.73,482.62 c 0.12,-10.88 -0.33,-22.8 7.93,-31.04 10.43,-10.39 25.75,-12.91 39.95,-10.63 q 0.47,0.08 0.45,0.54 l -0.87,24.33 a 0.96,0.95 88.3 0 1 -0.86,0.92 q -8.51,0.88 -17.53,2.35 c -11.22,1.83 -20.06,5.16 -28.09,13.92 q -1,1.08 -0.98,-0.39 z", + "m 283.92,476.78 q 12.55,-5.43 25.84,-3.32 0.36,0.06 0.36,0.42 0.41,19.6 -0.86,38.86 a 0.91,0.91 0 0 1 -1,0.85 c -13.44,-1.32 -28.43,-1.82 -41.54,1.88 q -1.32,0.37 -1.93,-0.86 c -9,-18.41 3.35,-31 19.13,-37.83 z", + "m 300.31,556.68 q -4.15,-2.21 -8.98,-2.91 -13.66,-2 -27.37,-1.31 a 0.95,0.95 0 0 1 -0.97,-0.72 q -2.73,-10.93 -1.37,-23.2 0.2,-1.78 1.77,-2.92 c 6.36,-4.65 14.69,-8.3 22.33,-8.94 q 12.38,-1.05 23.44,4.26 a 2.06,2.06 0 0 1 1.17,1.89 q -0.3,18.75 -1.38,35.86 -0.03,0.52 -0.55,0.61 c -2.7,0.45 -5.69,-1.34 -8.09,-2.62 z" ], right: [ - "M365.8 425.2c1.9-1.6 2.9-4.6 2.5-7.4q-.7-5.6-3.7-10.4c-2.0-3.1-5.3-4.6-8.7-4.8q-5.6-.3-10.7 1.9c-3.5 1.5-5.3 4.9-4.9 8.7q.5 6.2 4.4 11.0c2.5 3.2 6.2 4.4 10.1 3.8q6.5-.9 11.0-2.8z" + "m 349.65,553.77 c -5.34,0.78 -9.22,3.16 -13.94,5.24 q -1.59,0.69 -3.28,0.24 a 0.64,0.63 -83.8 0 1 -0.47,-0.59 q -1.23,-19.64 -1.28,-36.09 a 1.7,1.68 -13.4 0 1 0.95,-1.53 c 15.64,-7.64 31.83,-5.42 45.86,4.48 0.94,0.67 1.65,1.44 1.78,2.61 q 1.39,12.16 -1.2,23.23 -0.25,1.07 -1.34,1.03 -13.86,-0.54 -27.08,1.38 z", + "m 354.08,475.63 c 16.7,6.15 32.39,19.94 21.71,39.55 a 0.9,0.9 0 0 1 -1.05,0.43 c -13.38,-3.92 -27.7,-3.22 -41.96,-2.05 a 0.9,0.9 0 0 1 -0.97,-0.78 c -1.62,-12.74 -1.1,-26.27 -1.03,-38.85 a 0.48,0.47 86.4 0 1 0.4,-0.46 q 11.86,-1.91 22.9,2.16 z", + "m 378.34,483.09 c -8.04,-8.87 -17.3,-12.26 -29.19,-14.16 q -8.48,-1.35 -16.49,-2.17 a 1.05,1.04 2.2 0 1 -0.93,-1 l -0.83,-24.24 q -0.02,-0.53 0.51,-0.61 18.35,-2.62 31.52,4.43 14.18,7.59 15.53,22.29 0.76,8.32 0.7,15.15 -0.01,1.2 -0.82,0.31 z" ] ), @@ -347,10 +355,10 @@ enum FemaleFrontPaths { BodyPartPathData( slug: .lowerAbs, left: [ - "M288.1 595.5c-2.8-2.2-4.4-6.2-3.8-9.8q1.0-6.5 4.6-12.0c2.4-3.5 5.8-5.3 9.8-4.9q6.2.5 11.0 4.4c3.1 2.5 4.4 6.5 3.5 10.4q-1.5 6.2-6.2 10.1c-3.1 2.5-7.1 3.5-11.0 2.8q-4.6-.7-7.9-1z" + "m 263.89,560.38 c 18.37,-2.6 32.63,0.35 44.32,15.16 q 0.72,0.91 0.91,2.02 0.98,5.72 1.19,10.92 2.01,48.7 2.07,81.21 0.01,2.91 -2.63,5.03 c -2.77,2.21 -10.61,5.88 -13.52,2.38 -6.1,-7.32 -10.49,-16.08 -14.05,-25.36 q -14.5,-37.75 -18.65,-78.2 -0.6,-5.83 -0.33,-12.39 0.03,-0.68 0.69,-0.77 z" ], right: [ - "M361.2 595.5c2.8-2.2 4.4-6.2 3.8-9.8q-1.0-6.5-4.6-12.0c-2.4-3.5-5.8-5.3-9.8-4.9q-6.2.5-11.0 4.4c-3.1 2.5-4.4 6.5-3.5 10.4q1.5 6.2 6.2 10.1c3.1 2.5 7.1 3.5 11.0 2.8q4.6-.7 7.9-1z" + "m 362.23,642.32 c -4.21,12.26 -9.35,24.52 -17.49,34.79 q -0.9,1.12 -2.2,1.22 -6.54,0.54 -11.69,-3.91 c -1.34,-1.16 -2.37,-2.61 -2.35,-4.44 q 0.27,-32.33 1.7,-73.01 0.36,-10.37 1.51,-19.31 0.12,-0.89 0.67,-1.6 c 11.52,-15 26.64,-18.71 44.72,-15.65 a 0.85,0.84 -86 0 1 0.71,0.83 q 0.06,12.43 -1.93,25.22 -4.56,29.34 -13.65,55.86 z" ] ), @@ -358,10 +366,10 @@ enum FemaleFrontPaths { BodyPartPathData( slug: .frontDeltoid, left: [ - "M222.2 310.5c-2.9-1.6-4.6-4.9-4.4-8.3q.5-5.6 3.8-10.1c2.3-3.0 5.6-4.4 9.2-3.7q5.3 1.0 8.9 4.9c2.5 2.6 3.1 6.5 1.9 9.8q-1.9 5.3-6.7 8.0c-3.2 1.8-8.4 1.9-12.7-.6z" + "m 233,326.79 c -5.53,27.66 -26.78,45.52 -55.22,43.68 a 0.54,0.54 0 0 1 -0.5,-0.61 c 4.48,-32.74 28.09,-58.38 54.53,-76.41 q 2.3,-1.57 4.86,-0.86 a 1.61,1.61 0 0 1 1.18,1.72 Q 236,311.81 233,326.79 Z" ], right: [ - "M427.1 310.5c2.9-1.6 4.6-4.9 4.4-8.3q-.5-5.6-3.8-10.1c-2.3-3.0-5.6-4.4-9.2-3.7q-5.3 1.0-8.9 4.9c-2.5 2.6-3.1 6.5-1.9 9.8q1.9 5.3 6.7 8.0c3.2 1.8 8.4 1.9 12.7-.6z" + "m 463.02,370.48 c -23.85,1.37 -44.22,-11.24 -52.35,-33.91 q -2.31,-6.45 -3.64,-14.34 -2.64,-15.63 -3.89,-27.26 -0.28,-2.56 2.36,-2.63 1.96,-0.05 4.36,1.61 c 25.95,18.03 49.33,43.22 53.78,75.78 q 0.1,0.71 -0.62,0.75 z" ] ), diff --git a/Sources/MuscleMap/Data/MaleFrontPaths.swift b/Sources/MuscleMap/Data/MaleFrontPaths.swift index c1d2113..96d078b 100644 --- a/Sources/MuscleMap/Data/MaleFrontPaths.swift +++ b/Sources/MuscleMap/Data/MaleFrontPaths.swift @@ -260,14 +260,20 @@ enum MaleFrontPaths { BodyPartPathData( slug: .serratus, left: [ - "M268.5 460.2c-2.1-1.3-3.8-3.9-3.2-6.4q1.2-5.1 4.8-8.3c2.4-2.1 5.6-1.8 8.2-.4q4.3 2.3 6.1 7.1c1.2 3.2-.3 6.8-3.1 8.4q-5.8 3.3-12.8-.4z", - "M262.3 478.5c-1.8-1.6-2.9-4.2-2.1-6.7q1.5-4.8 5.4-7.2c2.6-1.6 5.8-.8 8.1 1.1q3.7 3.1 4.2 8.2c.3 3.4-1.5 6.3-4.6 7.4q-5.6 2-11-.8z", - "M258.1 498.3c-1.5-1.9-2.2-4.6-1.1-7q2-4.3 6.1-6.1c2.8-1.2 5.9.1 7.8 2.4q3.1 3.7 2.8 8.9c-.2 3.5-2.3 5.9-5.6 6.5q-5.3 1.2-10-4.7z" + "M264.21 435.53c-4.88-3.13-5.75-12.11-5.39-17.36q.03-.53.51-.75 1.8-.84 3.43.85 10.05 10.45 22.57 16.9c3.64 1.89 5.54 3.62 4.79 7.8q-.42 2.35-2.82 1.87-12.45-2.49-23.09-9.31z", + "M287.33 452.44c-4.05 4.46-10.38 11.38-16.28 14.3a.84.83 51.1 01-.9-.1c-6.29-5.17-12.54-18.97-14.21-25.09q-.91-3.34.85-8.81.12-.39.35-.05c2.41 3.65 4.59 7.74 8.67 9.76q10.18 5.05 21.27 9.01a.61.61 0 01.25.98z", + "M297.3 487.82c-7.36-4.23-16.68-11.37-20.55-17.57q-.32-.5.09-.92 8.72-9.04 19.84-17.87 1.46-1.17 2.81-1.67a.44.44 0 01.59.43c-.28 10.08-.4 20.42.65 30.43q.34 3.26-.68 6.15a1.9 1.9 0 01-2.75 1.02z", + "M257.35 456.18l13.68 16.63a1.86 1.82 22.9 01.4.95c.59 5.4-2.02 12.71-3.8 17.56q-.3.84-.84.13-11.85-15.55-9.77-35.17.04-.45.33-.1z", + "M271.69 494.07a1.53 1.52-61.8 01-.49-1.64l4.2-13.58a.98.98 0 011.51-.5c3.2 2.32 21.89 14.05 22.26 16.7q1.15 8.32.66 16.79a.9.9 0 01-1.34.73q-14.24-8.05-26.8-18.5z", + "M299.35 544.62c-7.52-6.03-16.15-13.43-24.23-21.24-6.93-6.7-6-17.19-4.88-26.06a.44.44 0 01.72-.28q13.31 11.88 28.41 21.38.43.27.6.75c2.33 6.49.95 18.37-.07 25.23q-.09.59-.55.22z" ], right: [ - "M456.8 460.2c2.1-1.3 3.8-3.9 3.2-6.4q-1.2-5.1-4.8-8.3c-2.4-2.1-5.6-1.8-8.2-.4q-4.3 2.3-6.1 7.1c-1.2 3.2.3 6.8 3.1 8.4q5.8 3.3 12.8-.4z", - "M462.9 478.5c1.8-1.6 2.9-4.2 2.1-6.7q-1.5-4.8-5.4-7.2c-2.6-1.6-5.8-.8-8.1 1.1q-3.7 3.1-4.2 8.2c-.3 3.4 1.5 6.3 4.6 7.4q5.6 2 11-.8z", - "M467.1 498.3c1.5-1.9 2.2-4.6 1.1-7q-2-4.3-6.1-6.1c-2.8-1.2-5.9.1-7.8 2.4q-3.1 3.7-2.8 8.9c.2 3.5 2.3 5.9 5.6 6.5q5.3 1.2 10-4.7z" + "M438.7 444.36c-2.09-4.03-.13-6.83 3.63-8.81 10.22-5.36 16.79-11 24.23-18.07a1.71 1.71 0 012.89 1.12c.33 4.74-.81 14.39-5.53 17.22-4.68 2.82-18.74 10.02-24.39 9.14q-.57-.09-.83-.6z", + "M457.39 466.73c-3.72-1.02-13.2-10.29-16.5-14.49a.52.52 0 01.24-.81q10.94-3.75 21.31-9c3.96-2.01 6.3-5.98 8.57-9.58q.38-.59.55.09c.82 3.33 1.54 6.17.38 9.58-2.55 7.44-7.62 18.79-13.66 24.01a.96.96 0 01-.89.2z", + "M428.43 487.22c-1.01-1.79-.82-4.55-.71-6.72q.78-15.08.48-30.27-.01-.59.55-.4 1.72.59 3.02 1.64 11.58 9.37 18.82 16.95c3.86 4.05-16.2 17.42-19.56 19.48a1.87 1.86 59.6 01-2.6-.68z", + "M470.76 456.28a.25.25 0 01.44.13q2.03 19.67-9.8 35.22-.37.48-.6-.08c-1.37-3.29-5.86-16.13-3.51-18.91q6.3-7.47 13.47-16.36z", + "M452.27 478.5c1.13.49 4.28 12.47 4.78 14.38q.14.5-.23.88-1.29 1.35-2.65 2.41-10.44 8.12-21.76 14.97-1.49.9-2.91 1.33a.81.81 0 01-1.05-.71q-.73-8.62.67-17.15.08-.47.44-.8c1.74-1.6 21.96-15.73 22.34-15.51a.58.03 31 00.37.2z", + "M428.22 519.14q.11-.36.43-.56 15.3-9.66 28.83-21.69a.43.42-22.6 01.71.29c.51 8.26 2.25 18.67-4.46 25.4q-11.8 11.84-25.03 22.09-.43.34-.49-.2c-.75-6.82-1.97-18.92.01-25.33z" ] ), @@ -275,10 +281,10 @@ enum MaleFrontPaths { BodyPartPathData( slug: .hipFlexors, left: [ - "M305.2 700.5c-3.8-2.1-7.2-6.3-8.1-10.7q-1.4-6.8 1.2-13.1c1.8-4.3 5.9-7.1 10.3-7.8q6.2-.9 11.4 2.8c3.5 2.5 5.2 6.9 4.8 11.2q-.6 6.7-5.3 11.9c-3.1 3.4-8.1 8.8-14.3 5.7z" + "M283 721L273.1 690L266.7 667.2L266.3 667.2L263 673.3L260 679.6L254.5 692.8L250.1 706.8L246.9 721Z" ], right: [ - "M421.5 700.5c3.8-2.1 7.2-6.3 8.1-10.7q1.4-6.8-1.2-13.1c-1.8-4.3-5.9-7.1-10.3-7.8q-6.2-.9-11.4 2.8c-3.5 2.5-5.2 6.9-4.8 11.2q.6 6.7 5.3 11.9c3.1 3.4 8.1 8.8 14.3 5.7z" + "M481.2 720.9L477.9 706.5L475.9 699.6L473.4 692.3L470.6 685L467.4 677.9L462.6 668.2L462 667.1L461.6 667.1L455.1 690L445.2 720.9Z" ] ), @@ -286,10 +292,10 @@ enum MaleFrontPaths { BodyPartPathData( slug: .upperChest, left: [ - "M275.8 345.1c5.2-4.8 14.3-8.2 21.6-9.4q12.8-1.8 24.5.5c6.4 1.2 11.2 6.3 13.4 12.5q3.2 9.1 1.8 18.8c-.9 6.2-5.1 10.4-10.8 12.9q-8.5 3.7-18.6 2.4c-6.8-.9-13.2-3.1-18.4-7.8q-7.7-6.9-13.5-29.9z" + "M358.5 365.1L358.1 358.2L357.3 352.3L356.2 346.3L354.9 341.2L353.3 336.6L351.2 331.9L348.9 328L346.3 324.6L344.2 322.5L342.3 321.1L339.9 319.7L337.8 319.1L327.9 317.7L316.7 317.2L308.6 317.5L300.9 318.1L297.2 318.7L292.8 319.8L287.1 321.8L281.9 324.2L276.2 327.5L271.5 330.8L267.7 334.1L264.8 337.1L262.4 340.2L260.5 343.5L258.8 347.9L257.3 353.2L256.2 358.9L255.5 365.1Z" ], right: [ - "M449.5 345.1c-5.2-4.8-14.3-8.2-21.6-9.4q-12.8-1.8-24.5.5c-6.4 1.2-11.2 6.3-13.4 12.5q-3.2 9.1-1.8 18.8c.9 6.2 5.1 10.4 10.8 12.9q8.5 3.7 18.6 2.4c6.8-.9 13.2-3.1 18.4-7.8q7.7-6.9 13.5-29.9z" + "M472.6 365.2L471.9 359.1L470.8 353.3L469.6 348.8L467.8 344.3L466 340.9L463.4 337.3L460.4 334.1L456.9 331.1L451.9 327.5L446.3 324.2L441.5 321.8L436.6 320L431.6 318.8L426.2 318L419.9 317.6L412.1 317.4L398.9 318L395 318.4L391.4 319.1L388.6 320L386 321.2L383.7 322.8L381.6 324.8L379.1 328.3L376.5 333L374.6 337.3L372.9 342.3L371.6 347.5L370.6 352.8L369.9 358.8L369.5 365.2Z" ] ), @@ -297,10 +303,10 @@ enum MaleFrontPaths { BodyPartPathData( slug: .lowerChest, left: [ - "M279.3 394.2c3.1-2.8 8.9-5.1 13.2-5.9q9.8-1.8 19.8.3c5.6 1.2 10.1 4.8 12.8 10.1q3.8 7.5 2.4 15.9c-1.1 6.1-5.8 9.8-11.2 11.8q-7.6 2.8-16.1 1.1c-5.7-1.1-10.8-3.8-14.5-8.5q-5.5-7-6.4-24.8z" + "M273.4 423.3L276.2 425.5L279.3 427.4L282.9 429.2L286.8 430.7L291.9 432.2L298.4 433.7L302.8 434.5L307.5 434.9L312.3 434.9L316.6 434.7L321.6 434.1L325.8 433.3L330 432.2L334.1 430.7L337.9 429L341.6 426.9L346.3 423.3L350.2 419.1L353.1 414.6L355.1 409.4L356.2 402.9L357.8 387.3L358.4 377.1L358.6 368.3L255.2 368.3L255.2 376.8L256 385.1L257.4 393.3L259.4 400.6L262.1 407.4L265.4 413.7L269.1 418.8Z" ], right: [ - "M446.2 394.2c-3.1-2.8-8.9-5.1-13.2-5.9q-9.8-1.8-19.8.3c-5.6 1.2-10.1 4.8-12.8 10.1q-3.8 7.5-2.4 15.9c1.1 6.1 5.8 9.8 11.2 11.8q7.6 2.8 16.1 1.1c5.7-1.1 10.8-3.8 14.5-8.5q5.5-7 6.4-24.8z" + "M416.7 435L424.2 434.6L430.8 433.6L437.1 432.2L443.1 430.2L447.6 428.1L451.7 425.6L455.4 422.7L459 418.9L462.6 414.2L465.5 409L467.9 403.5L470 397.1L471.5 390.4L472.5 383L472.9 375.6L472.8 368.4L369.4 368.4L369.6 375.9L370 383.8L372.3 404.7L373 408.5L374.1 412.1L375.4 414.9L377.2 417.9L380.3 421.5L384.3 425.1L388.9 428.1L393.8 430.5L399.1 432.4L405 433.9L410.9 434.8Z" ] ), @@ -308,10 +314,10 @@ enum MaleFrontPaths { BodyPartPathData( slug: .innerQuad, left: [ - "M316.5 780.2c-2.8-1.4-4.1-4.8-4.2-8.1q-.3-12.8 2.1-25.3c1.6-8.2 4.8-15.8 9.2-22.6q5.7-8.8 13.1-15.9c2.4-2.3 5.8-1.2 7.1 1.8q3.2 7.4 3.8 15.6c.8 11.2-.4 22.5-3.2 33.4q-2.8 10.8-8.1 18.4c-3.4 4.8-12.8 6.2-17.8 2.7z" + "M322.69 945.72c-3.73 6.14-10.77-2.43-12.6-5.6-3.16-5.47-2.62-14.93-1.78-20.81 4.03-28.09 5.6-52.81 3.48-80.78q-.06-.79.28-.08 15.77 32.83 14.26 68.9c-.4 9.54-2.94 22.48-2.91 34.13q.01 3.02-.73 4.24z" ], right: [ - "M410.2 780.2c2.8-1.4 4.1-4.8 4.2-8.1q.3-12.8-2.1-25.3c-1.6-8.2-4.8-15.8-9.2-22.6q-5.7-8.8-13.1-15.9c-2.4-2.3-5.8-1.2-7.1 1.8q-3.2 7.4-3.8 15.6c-.8 11.2.4 22.5 3.2 33.4q2.8 10.8 8.1 18.4c3.4 4.8 12.8 6.2 17.8 2.7z" + "M406.69 946.81c-3.24-2.77-1.48-10.64-2.01-14.71q-2.23-17.18-2.57-22.16c-1.75-25.07 3.61-49.11 13.98-71.92q.23-.51.2.05c-1.2 19.15-1.28 38.18.83 57.38q1.68 15.4 3.39 30.8c.43 3.92-.31 9.71-2.09 13.33-1.62 3.28-7.58 10.77-11.73 7.23z" ] ), @@ -319,10 +325,10 @@ enum MaleFrontPaths { BodyPartPathData( slug: .outerQuad, left: [ - "M258.4 810.5c-3.2-5.8-4.8-13.2-4.1-19.8q1.2-11.8 5.8-22.8c3.1-7.4 7.8-14.1 13.5-19.8q7.2-7.2 16.1-12.4c2.8-1.6 6.1.2 6.8 3.5q1.8 8.4 1.2 17.2c-.8 12.1-3.8 24.1-8.4 35.2q-4.6 11.1-11.8 19.8c-4.6 5.5-14.5 7.1-19.1-0.9z" + "M275.11 942.93q-2.42-2.18-3.57-5.24c-3.98-10.61-7.68-21.02-12.81-31.32-7.85-15.76-10.77-34.56-13.2-51.46-2.11-14.63-2.31-31.47-3.93-47.18-.22-2.16-1.04-12.78.46-13.79q1.36-.92 2.08.55c1.5 3.08 3.12 6.12 3.66 9.58q8.21 52.38 26.36 102.15c2.87 7.87 9.98 30.5 1.85 36.74a.71.7-42.5 01-.9-.03z" ], right: [ - "M468.3 810.5c3.2-5.8 4.8-13.2 4.1-19.8q-1.2-11.8-5.8-22.8c-3.1-7.4-7.8-14.1-13.5-19.8q-7.2-7.2-16.1-12.4c-2.8-1.6-6.1.2-6.8 3.5q-1.8 8.4-1.2 17.2c.8 12.1 3.8 24.1 8.4 35.2q4.6 11.1 11.8 19.8c4.6 5.5 14.5 7.1 19.1-0.9z" + "M451.79 942.6c-9.95-10.01 4.97-42.91 8.94-55.41q12.55-39.53 19.27-80.47c.49-2.97 2.64-12.34 5.41-13.28a.83.83 0 011.09.64q.74 4 .45 7.92c-1.99 26.52-3.37 58.99-11.01 87.73q-2.53 9.5-7.46 18.8c-4.38 8.24-6.97 16.72-10.08 25.27q-1.66 4.54-4.55 8.63a1.35 1.35 0 01-2.06.17z" ] ), @@ -330,10 +336,14 @@ enum MaleFrontPaths { BodyPartPathData( slug: .upperAbs, left: [ - "M315.8 448.2c-2.1-1.8-3.2-5.1-2.8-8.1q.8-6.2 4.1-11.4c2.2-3.4 5.8-5.1 9.6-5.3q6.2-.3 11.8 2.1c3.8 1.6 5.8 5.4 5.4 9.6q-.6 6.8-4.8 12.1c-2.8 3.5-6.8 4.8-11.1 4.2q-7.1-1-12.2-3.2z" + "M311.02 531.71a.23.23 0 01-.19-.21q-.39-10.47 1.9-20.76c1.26-5.69 7.66-9.9 13.1-12.9 9.09-5.01 18.93-11.15 28.56-14.92a1.24 1.21-42.6 01.94.03c3.28 1.52 4.78 3.87 4.82 7.68q.13 13.16-.15 26.31c-.08 3.85.78 8.39-.87 13.1q-.17.46-.59.72-2.65 1.65-4.29 1.82-21.06 2.22-43.23-.87z", + "M321 577.76c-5.17-.33-8.71-.44-10-6.26q-3.2-14.44-.59-27.83.11-.53.64-.63c7.58-1.44 13.62-2.45 22.45-4.56q11.5-2.76 23.94-1.88c3.67.26 3.3 3.46 3.4 6.21q.46 12.55-.33 26.94-.25 4.41-1.81 8.08-.21.49-.73.6-1.39.28-3.22.29-16.89.14-33.75-.96z", + "M347.73 429.25c7.46-3.61 10.5 6.27 10.99 11.52.48 5.06 3.46 30.61-2.78 32.93q-4.17 1.55-6.89 3.33-17.56 11.54-35.88 21.46a1.6 1.59-21.9 01-2.3-.98c-2.87-10.41-10.59-43.96 1.66-50.95 11.3-6.45 23.96-11.86 35.2-17.31z" ], right: [ - "M411.5 448.2c2.1-1.8 3.2-5.1 2.8-8.1q-.8-6.2-4.1-11.4c-2.2-3.4-5.8-5.1-9.6-5.3q-6.2-.3-11.8 2.1c-3.8 1.6-5.8 5.4-5.4 9.6q.6 6.8 4.8 12.1c2.8 3.5 6.8 4.8 11.1 4.2q7.1-1 12.2-3.2z" + "M371.94 473.31c-5.46-2.59-2.97-24.26-2.77-29.56.25-6.8 2.41-18.63 12.64-13.8q16.26 7.67 32.34 15.72 6.18 3.1 7.13 10.05c.58 4.26 1.35 8.49 1.07 12.72q-.84 12.55-4.33 26.56-.54 2.16-1.1 3.44-.25.58-.81.31c-15.78-7.29-30.79-19.08-44.17-25.44z", + "M382.57 533.27c-4.17-.18-9.56-.3-13.15-2.69q-.17-.11-.24-.31c-1.82-5.55-.86-11.17-.96-15.66-.18-8.4-.78-17.36.06-25.71.29-2.85 1.88-4.42 4.15-5.79q.42-.26.91-.19 1.71.25 3.21 1.03 12.48 6.44 24.75 13.26c4.96 2.75 12.21 7.02 13.72 12.41q2.93 10.56 2.39 21.49a.77.76-1.8 01-.67.71q-16.89 2.18-34.17 1.45z", + "M373.75 578.69c-2.47 0-4.31.22-5-2.7-1.8-7.7-3.05-34.29-.19-38.81q.27-.43.77-.47 13.14-1.24 25.77 1.83c8.41 2.04 14.51 3.01 21.85 4.36a1.29 1.28.6 011.05 1.07q2.16 14.12-.73 28.07c-1.08 5.24-5.22 5.26-10.36 5.63q-14.26 1.04-33.16 1.02z" ] ), @@ -341,10 +351,10 @@ enum MaleFrontPaths { BodyPartPathData( slug: .lowerAbs, left: [ - "M320.1 620.5c-3.1-2.4-4.8-6.8-4.2-10.8q1.1-7.2 5.1-13.2c2.6-3.8 6.4-5.8 10.8-5.4q6.8.6 12.1 4.8c3.4 2.7 4.8 7.1 3.8 11.4q-1.6 6.8-6.8 11.1c-3.4 2.8-7.8 3.8-12.1 3.1q-5.1-.8-8.7-1z" + "M350.35 712.81c-29.15-9.93-37.98-100.69-39.47-126.61a.99.99 0 01.33-.8c3.58-3.26 27.61-1.47 34.62-.93 4.41.34 15.27 1.31 15.26 7.53-.05 40.77.64 82.05-1.96 122.72a1.29 1.29 0 01-1.86 1.08c-2.3-1.14-4.12-2.04-6.92-2.99z" ], right: [ - "M407.2 620.5c3.1-2.4 4.8-6.8 4.2-10.8q-1.1-7.2-5.1-13.2c-2.6-3.8-6.4-5.8-10.8-5.4q-6.8.6-12.1 4.8c-3.4 2.7-4.8 7.1-3.8 11.4q1.6 6.8 6.8 11.1c3.4 2.8 7.8 3.8 12.1 3.1q5.1-.8 8.7-1z" + "M416.32 584.73q1.14.41 1.07 1.62c-1.62 26.44-9.96 116.68-40.43 126.74-2.27.75-4.15 2.12-6.35 2.73q-1.18.33-1.3-.89-.86-9.2-1.06-17.75c-.83-35.67-.91-71.2-1.01-106.88q0-.5.31-.89c4.95-6.46 41.69-7.25 48.77-4.68z" ] ), @@ -352,10 +362,10 @@ enum MaleFrontPaths { BodyPartPathData( slug: .frontDeltoid, left: [ - "M261.2 338.5c-3.2-1.8-5.1-5.4-4.8-9.1q.5-6.2 4.2-11.1c2.5-3.3 6.2-4.8 10.1-4.1q5.8 1.1 9.8 5.4c2.7 2.9 3.4 7.1 2.1 10.8q-2.1 5.8-7.4 8.8c-3.5 2-9.2 2.1-14-.7z" + "M273.5 311.3L268.3 308.1L263.1 305.8L258 304.2L252.3 303.4L247.3 303.4L241.8 304.2L236.4 305.8L231.1 308.1L231.1 391.5L243 376.7L245 373.5L246.4 370.3L247.4 366.9L247.8 364L247.8 350.1L248.2 344.5L249.3 340.1L251.2 336.3L254.3 332.7L258.6 329.6L263.4 327.2L274.6 322.4L278.2 320.4L278.4 319.9L278.1 318L277.1 315.1L275.4 312.8Z" ], right: [ - "M464.1 338.5c3.2-1.8 5.1-5.4 4.8-9.1q-.5-6.2-4.2-11.1c-2.5-3.3-6.2-4.8-10.1-4.1q-5.8 1.1-9.8 5.4c-2.7 2.9-3.4 7.1-2.1 10.8q2.1 5.8 7.4 8.8c3.5 2 9.2 2.1 14-.7z" + "M450.9 321L459.9 324.5L466.8 328.1L473 332.3L475.1 334.2L477 336.6L478.9 340.2L480 344.6L480.3 349.1L480.3 362.7L480.9 366.9L481.9 370.4L483.8 374.7L486.8 379.2L490.6 384.1L497.1 391.4L497.1 307.9L493.6 306.3L489.9 305L486.1 304.1L482.7 303.6L479.3 303.4L475.7 303.5L472.1 304L468.4 304.9L464 306.4L459.5 308.3L456.3 310.1L453.6 312.1L451.5 314.7L450 318L449.7 319.9L449.9 320.4Z" ] ), diff --git a/Sources/MuscleMap/MuscleMap.docc/Accessibility.md b/Sources/MuscleMap/MuscleMap.docc/Accessibility.md new file mode 100644 index 0000000..eef843e --- /dev/null +++ b/Sources/MuscleMap/MuscleMap.docc/Accessibility.md @@ -0,0 +1,19 @@ +# Accessibility + +Make the body map usable with VoiceOver. + +## Overview + +``BodyView`` exposes each visible muscle as an accessibility element. No setup is needed. + +Each element has: + +- **Label:** the localized muscle name. A muscle drawn on both sides gets one element per side, labeled for example "Biceps, Left" and "Biceps, Right". +- **Value:** "Selected" or "Not selected". +- **Hints and actions:** double-tap selects the muscle, and a "Long press for details" action calls ``BodyView/onMuscleLongPressed(duration:action:)``. + +Elements are ordered from top to bottom, and the two sides of a muscle are read one after the other. Activating an element calls ``BodyView/onMuscleSelected(_:)`` with the same muscle and ``MuscleSide`` that a touch on that spot would report. + +## Localization + +Muscle names, sides and accessibility strings are localized in 11 languages: Arabic, Chinese (Simplified), English, French, German, Japanese, Korean, Portuguese (Brazil), Russian, Spanish and Turkish. Use ``Muscle/displayName`` and ``MuscleSide/displayName`` to show the same names in your own UI. diff --git a/Sources/MuscleMap/MuscleMap.docc/GettingStarted.md b/Sources/MuscleMap/MuscleMap.docc/GettingStarted.md index 80b0d75..ad07fa7 100644 --- a/Sources/MuscleMap/MuscleMap.docc/GettingStarted.md +++ b/Sources/MuscleMap/MuscleMap.docc/GettingStarted.md @@ -8,18 +8,20 @@ MuscleMap is a pure SwiftUI package with no external dependencies. It supports i ## Adding MuscleMap to Your Project +With CocoaPods, add `pod 'MuscleMap', '~> 1.9.0'` to your `Podfile`. With Swift Package Manager: + Add MuscleMap as a Swift Package dependency in Xcode: 1. Open your project in Xcode. 2. Go to **File → Add Package Dependencies**. -3. Enter the repository URL. +3. Enter `https://github.com/melihcolpan/MuscleMap.git`. 4. Select the latest version and add it to your target. Or add it to your `Package.swift`: ```swift dependencies: [ - .package(url: "https://github.com/AcademyOfGames/MuscleMap", from: "1.5.0") + .package(url: "https://github.com/melihcolpan/MuscleMap.git", from: "1.9.0") ] ``` diff --git a/Sources/MuscleMap/MuscleMap.docc/HeatmapGuide.md b/Sources/MuscleMap/MuscleMap.docc/HeatmapGuide.md index 37ab36d..0f37385 100644 --- a/Sources/MuscleMap/MuscleMap.docc/HeatmapGuide.md +++ b/Sources/MuscleMap/MuscleMap.docc/HeatmapGuide.md @@ -59,6 +59,8 @@ Available interpolation modes: - ``ColorInterpolation/step(count:)`` — discrete color bands - ``ColorInterpolation/custom(_:)`` — provide your own curve function +A color scale can carry its own interpolation: ``HeatmapColorScale/workoutStepped`` is the workout scale with five steps, and ``HeatmapColorScale/thermalSmooth`` eases in and out. That interpolation is used by default. An interpolation set with ``BodyView/heatmapInterpolation(_:)`` or a ``HeatmapConfiguration`` takes precedence when it is not ``ColorInterpolation/linear``. + ## Gradient Fill Enable intra-muscle gradient fills where each muscle shows a gradient from low to high intensity: diff --git a/Sources/MuscleMap/MuscleMap.docc/MuscleMap.md b/Sources/MuscleMap/MuscleMap.docc/MuscleMap.md index 850f733..b521e9d 100644 --- a/Sources/MuscleMap/MuscleMap.docc/MuscleMap.md +++ b/Sources/MuscleMap/MuscleMap.docc/MuscleMap.md @@ -35,6 +35,7 @@ BodyView(gender: .male, side: .front) - ``MuscleSide`` - ``MuscleHighlight`` - ``MuscleFill`` +- ### Heatmaps @@ -60,3 +61,8 @@ BodyView(gender: .male, side: .front) - - ``MuscleMapView`` - ``HeatmapLegendUIView`` + +### Accessibility and Performance + +- +- diff --git a/Sources/MuscleMap/MuscleMap.docc/Performance.md b/Sources/MuscleMap/MuscleMap.docc/Performance.md new file mode 100644 index 0000000..e81d9a5 --- /dev/null +++ b/Sources/MuscleMap/MuscleMap.docc/Performance.md @@ -0,0 +1,30 @@ +# Performance + +Keep body views fast to appear and to redraw. + +## Overview + +The body artwork is a set of SVG paths. MuscleMap parses each path once, caches it for the life of the app, and only scales it for each view size. Redrawing a body, for example when a highlight changes, reuses those cached paths. + +## Preloading the Artwork + +Creating a ``BodyView`` starts parsing all four bodies in the background. To have the artwork ready before the first body appears, start it at launch with ``BodyView/preloadArtwork()``: + +```swift +@main +struct WorkoutApp: App { + init() { + BodyView.preloadArtwork() + } + + var body: some Scene { + WindowGroup { ContentView() } + } +} +``` + +Calling it more than once has no extra cost. + +## Swift Concurrency + +On a Swift 6 toolchain, the package builds in the Swift 6 language mode with complete concurrency checking. Views are main-actor isolated like any SwiftUI view; the shared path cache is safe to use from any thread. diff --git a/Sources/MuscleMap/MuscleMap.docc/SubGroupsAndRegions.md b/Sources/MuscleMap/MuscleMap.docc/SubGroupsAndRegions.md new file mode 100644 index 0000000..9d696d4 --- /dev/null +++ b/Sources/MuscleMap/MuscleMap.docc/SubGroupsAndRegions.md @@ -0,0 +1,57 @@ +# Sub-Groups and Regions + +Highlight parts of a muscle, and check which muscles a view can draw. + +## Overview + +Several muscles are divided into sub-groups, such as the upper and lower chest or the inner and outer quadriceps. Each sub-group is cut from its parent muscle's artwork, so it lines up exactly with the parent's outline. + +Sub-groups are hidden by default. Call ``BodyView/showSubGroups()`` to draw them and to make taps return the sub-group instead of its parent: + +```swift +BodyView(gender: .male, side: .front) + .showSubGroups() + .highlight(.upperChest, color: .red) + .highlight(.lowerChest, color: .orange) + .highlight(.innerQuad, color: .blue) +``` + +A sub-group without a highlight of its own shows its parent's highlight, so you can highlight a parent and emphasize one part of it: + +```swift +BodyView(gender: .male, side: .front) + .showSubGroups() + .highlight(.chest, color: .red, opacity: 0.4) + .highlight(.upperChest, color: .red) +``` + +Use ``Muscle/subGroups`` and ``Muscle/parentGroup`` to navigate the hierarchy. + +## Always-Visible Sub-Groups + +``Muscle/ankles``, ``Muscle/adductors`` and ``Muscle/neck`` are drawn even when sub-groups are hidden. In that mode a tap on them returns the parent muscle. See ``Muscle/isAlwaysVisibleSubGroup``. + +## Back Regions + +The back views have a few extra regions: + +- ``Muscle/upperTrapezius`` and ``Muscle/lowerTrapezius``: the trapezius above and below the rhomboids. On the front views, the visible trapezius is its upper part. +- ``Muscle/rearDeltoid``: the deltoid as seen from behind. +- ``Muscle/rhomboids``: inside the trapezius. They are painted only while highlighted or selected, so an unhighlighted body and a ``Muscle/trapezius`` highlight look the same as without them. +- ``Muscle/rotatorCuff``: the infraspinatus area above the shoulder blade. Without a highlight of its own, it shows the ``Muscle/upperBack`` highlight. + +With sub-groups hidden, a tap on the rhomboids or the rotator cuff returns ``Muscle/trapezius`` or ``Muscle/upperBack``. + +## Checking What a View Can Draw + +Every muscle is drawn in at least one view, but many only on the front or on the back. Check a muscle mapping with ``Muscle/isDrawable(gender:side:)``, for example in a unit test: + +```swift +func testEveryMappedMuscleIsVisible() { + for muscle in myBackDayMuscles { + XCTAssertTrue(muscle.isDrawable(gender: .male, side: .back), "\(muscle)") + } +} +``` + +The female back view has no ``Muscle/head`` path, because the hair covers the head completely. diff --git a/Sources/MuscleMap/MuscleMap.docc/UIKitIntegration.md b/Sources/MuscleMap/MuscleMap.docc/UIKitIntegration.md index af2a169..31eb566 100644 --- a/Sources/MuscleMap/MuscleMap.docc/UIKitIntegration.md +++ b/Sources/MuscleMap/MuscleMap.docc/UIKitIntegration.md @@ -34,7 +34,7 @@ class ViewController: UIViewController { ## Highlighting Muscles -Use the ``MuscleMapView/highlight(_:color:opacity:)`` method with UIKit colors: +Use the ``MuscleMapView/highlight(_:color:opacity:)-(Muscle,_,_)`` method with UIKit colors: ```swift muscleMap.highlight(.chest, color: .systemRed) diff --git a/Tests/MuscleMapTests/SnapshotTests.swift b/Tests/MuscleMapTests/SnapshotTests.swift index 5d61a2b..f961e6a 100644 --- a/Tests/MuscleMapTests/SnapshotTests.swift +++ b/Tests/MuscleMapTests/SnapshotTests.swift @@ -70,6 +70,23 @@ final class SnapshotTests: XCTestCase { } } + func testFrontSubGroups() throws { + for gender in BodyGender.allCases { + let view = BodyView(gender: gender, side: .front) + .showSubGroups() + .highlight(.upperChest, color: Self.red) + .highlight(.lowerChest, color: Self.orange) + .highlight(.frontDeltoid, color: Self.purple) + .highlight(.upperAbs, color: Self.yellow) + .highlight(.lowerAbs, color: Self.teal) + .highlight(.serratus, color: Self.red) + .highlight(.hipFlexors, color: Self.teal) + .highlight(.innerQuad, color: Self.blue) + .highlight(.outerQuad, color: Self.purple) + try assertSnapshot(view, named: "\(gender.rawValue)_front_subgroups") + } + } + // MARK: - Helpers private func assertSnapshot(_ view: V, named name: String, file: StaticString = #filePath, line: UInt = #line) throws { diff --git a/Tests/MuscleMapTests/SubGroupTests.swift b/Tests/MuscleMapTests/SubGroupTests.swift index a23ac6b..d24c156 100644 --- a/Tests/MuscleMapTests/SubGroupTests.swift +++ b/Tests/MuscleMapTests/SubGroupTests.swift @@ -393,3 +393,27 @@ final class SubGroupTests: XCTestCase { XCTAssertEqual(Muscle.allCases.count, 36) } } + +final class SubGroupShapeTests: XCTestCase { + + /// Every sub-group shape is cut from its parent's artwork, so it must lie inside the parent. + func testSubGroupsLieInsideTheirParent() { + for gender in BodyGender.allCases { + for side in BodySide.allCases { + let parts = BodyPathProvider.paths(gender: gender, side: side) + for part in parts { + guard let muscle = part.slug.muscle, let parent = muscle.parentGroup, + !muscle.isAlwaysVisibleSubGroup else { continue } + let parentRect = parts.filter { $0.slug.muscle == parent } + .flatMap(\.allPaths) + .map { PathBuilder.buildPath(from: $0, scale: 1, offsetX: 0, offsetY: 0).boundingRect } + .reduce(CGRect.null) { $0.union($1) } + for svg in part.allPaths { + let rect = PathBuilder.buildPath(from: svg, scale: 1, offsetX: 0, offsetY: 0).boundingRect + XCTAssertTrue(parentRect.insetBy(dx: -1, dy: -1).contains(rect), "\(muscle) outside \(parent) on \(gender) \(side)") + } + } + } + } + } +} diff --git a/Tests/MuscleMapTests/__Snapshots__/female_front_subgroups.png b/Tests/MuscleMapTests/__Snapshots__/female_front_subgroups.png new file mode 100644 index 0000000..16a97a2 Binary files /dev/null and b/Tests/MuscleMapTests/__Snapshots__/female_front_subgroups.png differ diff --git a/Tests/MuscleMapTests/__Snapshots__/male_front_subgroups.png b/Tests/MuscleMapTests/__Snapshots__/male_front_subgroups.png new file mode 100644 index 0000000..3480d0d Binary files /dev/null and b/Tests/MuscleMapTests/__Snapshots__/male_front_subgroups.png differ diff --git a/Tools/ScreenshotGenerator/Sources/ScreenshotGenerator/main.swift b/Tools/ScreenshotGenerator/Sources/ScreenshotGenerator/main.swift index 3416a58..89997ef 100644 --- a/Tools/ScreenshotGenerator/Sources/ScreenshotGenerator/main.swift +++ b/Tools/ScreenshotGenerator/Sources/ScreenshotGenerator/main.swift @@ -90,6 +90,19 @@ let screenshots: [Screenshot] = [ MuscleIntensity(muscle: .forearm, intensity: 0.25), ], colorScale: .workoutStepped) }, + Screenshot("front_subgroups") { + BodyView(gender: .male, side: .front) + .showSubGroups() + .highlight(.upperChest, color: .red) + .highlight(.lowerChest, color: .orange) + .highlight(.frontDeltoid, color: .purple) + .highlight(.upperAbs, color: .yellow) + .highlight(.lowerAbs, color: .green) + .highlight(.serratus, color: .pink) + .highlight(.hipFlexors, color: .teal) + .highlight(.innerQuad, color: .blue) + .highlight(.outerQuad, color: .indigo) + }, Screenshot("back_regions") { BodyView(gender: .male, side: .back) .showSubGroups()