{"id":15055344,"url":"https://github.com/nutterfi/shapes","last_synced_at":"2025-04-10T03:37:03.977Z","repository":{"id":112756697,"uuid":"340272854","full_name":"nutterfi/Shapes","owner":"nutterfi","description":"A Swift package to expand the library of usable shapes in SwiftUI projects","archived":false,"fork":false,"pushed_at":"2024-02-25T04:37:44.000Z","size":130,"stargazers_count":14,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-04-25T22:20:33.893Z","etag":null,"topics":["ios","macos","swift","swiftui"],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nutterfi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-19T05:57:19.000Z","updated_at":"2024-08-02T21:45:17.455Z","dependencies_parsed_at":"2024-02-25T05:26:27.382Z","dependency_job_id":"04a10a3d-62ff-49d9-8a0e-3079e707ee55","html_url":"https://github.com/nutterfi/Shapes","commit_stats":null,"previous_names":[],"tags_count":44,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nutterfi%2FShapes","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nutterfi%2FShapes/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nutterfi%2FShapes/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nutterfi%2FShapes/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nutterfi","download_url":"https://codeload.github.com/nutterfi/Shapes/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248153708,"owners_count":21056484,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","macos","swift","swiftui"],"created_at":"2024-09-24T21:41:05.277Z","updated_at":"2025-04-10T03:37:03.959Z","avatar_url":"https://github.com/nutterfi.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Shapes\n\n## What's this all about?\n\nThis Swift package can be used to easily build SwiftUI shapes that conform to the `Shape` protocol. Most of the well-known shapes are in here, and some not-so-well-known shapes are here too!\n\n## Requirements\nShapes requires a minimum of macOS 12, iOS 15, and tvOS 15.\n\n## Under construction\n\n ###### The goal of this page is to list all available shapes and include code examples and visuals.\n\n ###### TODO: Light/dark mode images\n---\n\n### InsetShape\n\nEach shape defined in this project adheres to SwiftUI's `Shape` protocol. It is also desirable to provide inset capabilities to these custom shapes, similar to the built-in SwiftUI shapes.\n\nThe `InsetShape` type is introduced as a wrapper type, similar to `RotatedShape`, `OffsetShape`, etc. `InsetShape` conforms to `InsettableShape` and provides a way to inset any given shape.\n\nUsage: `InsetShape(shape: MyCustomShape(), inset: amount)`\n\nAdditionally, a `Shape` extension method has been provided to make this easy to use:\n\nUsage: `MyShape().inset(amount: amount)` // Returns InsetShape\u003cMyShape\u003e\n\n### Polygon\n\nA `Polygon` is a closed shape that consists of multiple line segments. It is defined in this project as a protocol:\n\n```swift\n/// A plane figure that is described by a finite number of straight line segments connected to form a closed polygonal chain\npublic protocol Polygon {\n  var sides: Int { get }\n  func vertices(in rect: CGRect) -\u003e [CGPoint]\n}\n```\nEach `Polygon` is defined by the number of sides. In order for the shape to be drawn, the `vertices` of each polygon are also required. These are managed via a `CGPoint` array. The vertices are obtained with a method in order to determine the position given a `CGRect`\n\nNot all shapes in this library will conform to `Polygon` because they may include curved surfaces.\n\n#### Polygon Example: SimplePolygon\n\nThe simplest Polygon example in the library is appropriately named `SimplePolygon`. Provide an array of ratios in the initializer to construct a polygon with points around the unit circle that are contained in the shape's frame.\n\nFor example, if one were to define a polygon with points at 0.33, 0.67, and 1:\n\n```swift\nSimplePolygon(ratios: [0.33, 0.67, 1])\n```\nthis tells the library to generate a polygon with vertices at 33%, 67%, and 100% distance traveled around the unit circle. (0% starts at the point facing east in the following illustration)\n\n\u003cimg src=\"https://user-images.githubusercontent.com/79107267/181698364-85a7b21b-22e1-4c70-baa8-8a7a35590df3.png\" width=\"200\" height=\"200\" /\u003e\n\nThe code used to generate this diagram is\n\n```swift\nstruct SimplePolygon_Previews: PreviewProvider {\n  static var previews: some View {\n    ZStack {\n      Circle().stroke()  // the unit circle\n      SimplePolygon(ratios: [0.33, 0.67, 1])\n        .foregroundStyle(Color.blue)\n    }\n    .border(Color.purple)\n  }\n}\n```\nYou can provide as many ratios as desired, in any order, and the shape will render them appropriately:\n\n```swift\nstruct SimplePolygon2_Previews: PreviewProvider {\n  static var previews: some View {\n    ZStack {\n      Circle().stroke() // the unit circle\n      SimplePolygon(ratios: [0.1, 0.5, 0.756, 0.3, 0.4])\n        .foregroundStyle(Color.blue)\n    }\n    .border(Color.purple)\n  }\n}\n```\n\n\u003cimg src=\"https://user-images.githubusercontent.com/79107267/181698606-d1c11da2-8d02-421a-9ec6-e5d5c3825807.png\" width=\"200\" height=\"200\" /\u003e\n\nNOTE: For non-square frames, the polygon will be rendered in the center of the frame. The unit circle is measured based on the smallest dimension of the `CGRect`:\n\n```swift\nstruct SimplePolygon3_Previews: PreviewProvider {\n  static var previews: some View {\n    ZStack {\n      Circle().stroke()\n      SimplePolygon(ratios: [0.1, 0.5, 0.756, 0.3, 0.4])\n        .foregroundStyle(Color.blue)\n    }\n    .border(Color.purple)\n    .frame(width: 256, height: 128)\n  }\n}\n```\n\n\u003cimg src=\"https://user-images.githubusercontent.com/79107267/181698903-ad65fa1a-c1f4-48bb-bdb6-e4848ca1bff4.png\" width=\"400\" height=\"200\" /\u003e\n\n### Polygon Example: ConvexPolygon\n\nA convex polygon, also known as a Regular Polygon, is a polygon whose sides are all equal length and whose vertices are equally distributed around the unit circle.\n\n`ConvexPolygon` is defined as a struct that conforms to the `RegularPolygon` protocol. As a protocol, `RegularPolygon` requires the following properties and methods:\n\n```swift\n/// A polygon with equal-length sides and equally-spaced vertices along a circumscribed circle\npublic protocol RegularPolygon: Polygon {}\n```\nThat's right, it's empty! `RegularPolygon` conforms to `Polygon` without any additional requirements. The reason that `RegularPolygon` exists is to implement the `vertices(in: CGRect)` method via a protocol extension:\n\n```swift\npublic extension RegularPolygon {\n  \n  /// obtains the equally spaced points of a polygon around a circle inscribed in rect, arranged clockwise starting at the top of the unit circle\n  func vertices(in rect: CGRect) -\u003e [CGPoint] {\n    vertices(in: rect, offset: .zero)\n  }\n  \n  /// obtains the equally spaced points of a polygon around a circle inscribed in rect, arranged clockwise starting at the top of the unit circle, with any additional rotational offset\n  func vertices(in rect: CGRect, offset: Angle = .zero) -\u003e [CGPoint] {\n    let r = min(rect.size.width, rect.size.height) / 2\n    let origin = CGPoint(x: rect.midX, y: rect.midY)\n    let array: [CGPoint] = Array(0 ..\u003c sides).map {\n      let theta = 2 * .pi * CGFloat($0) / CGFloat(sides) + CGFloat(offset.radians) - CGFloat.pi / 2  // pointing north!\n      return CGPoint(x: origin.x + r * cos(theta), y: origin.y + r * sin(theta))\n    }\n    return array\n  }\n}\n```\n\nIn the code above, I made the conscious choice to rotate the origin of the unit circle to be facing up. Most polygon drawings I've seen in textbooks and the internet (no citation provided, sorry) show a corner pointing to the top of the image, so that's the convention that is used here.\n\nThe second method, `vertices(in: CGRect, offset: Angle)` allows the user to specify additional rotational offset as desired.\n\nThese methods are useful to obtain the vertices for other shapes that are _not_ polygons as well, e.g. `ReuleauxPolygon` and `Torx` with their curved sides.\n\nNow that we understand how `RegularPolygon` is used, it's time to learn about `ConvexPolygon`. The initializer takes a number of sides, like so:\n\n```swift\nConvexPolygon(sides: 7)\n```\nThis shape can be illustrated with the following example: \n\n```swift\nstruct ConvexPolygon_Previews: PreviewProvider {\n  static var previews: some View {\n    ZStack {\n      Circle() // unit circle\n        .strokeBorder(Color.red, lineWidth: 10)\n        \n      ConvexPolygon(sides: 7)\n        .strokeBorder(Color.green.opacity(0.8), lineWidth: 10)\n    }\n  }\n}\n```\n\n\u003cimg src=\"https://user-images.githubusercontent.com/79107267/181699071-9e29604a-cf0c-4a38-b888-5032edf7dac2.png\" width=\"200\" height=\"200\" /\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnutterfi%2Fshapes","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnutterfi%2Fshapes","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnutterfi%2Fshapes/lists"}