npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@amaplex-software/shapeit

v0.1.6

Published

Shape detection and generation utility library for Node.JS or the web-browser

Downloads

105

Readme

Shapeit

Shapeit (shape it) is a utility library for Node.JS or the web-browser which will take a set of vertices representing a roughly drawn shape as an input and will output a fixed shape along with its name. Possible shape estimations are taken from a shape atlas based on a set of threshold constants. Both shape atlas and threshold constants can be explicitly provided by the user, although preexisting values will be used as a fallback if your'e looking for a basic, yet decent functionality.

Docs

Shapeit is a function which accepts a single parameter of a roughly drawn shape. The given shape is an array of number pairs representing 2D vertices with X and Y values. A simple use case can be seen below:

import shapeit from 'shapeit'

const uglySquare = [
  [-0.1, 0   ],
  [4.9 , 0.2 ],
  [10.1, -0.1],
  [10.2, 4.9 ],
  [9.9 , 9.8 ],
  [5.1 , 9.9 ],
  [0.1 , 10  ],
  [-0.1, 4.7 ],
  [0.1 , -0.1],
]

const prettySquare = shapeit(uglySquare)

assert(prettySquare, [[Number, Number]])
assert(prettySquare.name, 'square')

The result would also be a shape, but with a much reduced number of vertices that were best aligned with one of the shapes presented in the shape atlas. The resulted shape would also have an additional name field representing the name of the shape. The only exception would be a circle result, where we would have an object with a center and radius fields:

import shapeit from 'shapeit'

const uglyCircle = [
  [1    , 0    ],
  [0.86 , 0.49 ],
  [0.5  , 0.86 ],
  [6.12 , 1    ],
  [-0.49, 0.86 ],
  [-0.86, 0.5  ],
  [-1   , 1.22 ],
  [-0.86, -0.49],
  [-0.5 , -0.86],
  [-1.83, -1   ],
  [0.49 , -0.86],
  [0.86 , -0.5 ],
]

const prettyCircle = shapeit(uglyCircle)

assert(prettyCircle.center, [Number, Number])
assert(prettyCircle.radius, Number)
assert(prettySquare.name, 'circle')

A new Shapeit instance can be created with custom configuration using the new() method:

import shapeit from 'shapeit'

const shapethat = shapeit.new({
  atlas: {},
  output: {},
  thresholds: {},
})

In addition, an existing Shapeit instance configuration can be modified using the modify() method:

import shapeit from 'shapeit'

modify.new({
  atlas: {},
  output: {},
  thresholds: {},
})

More information regards the configuration options used in the examples above can be found further in the docs section. In addition, here's a list with quick references for each configuration field documentation section:

shape atlas

As stated in the initial summary, shape atlas and threshold constants can be provided. Let's begin with the shape atlas. The shape atlas is an atlas which contain possible shape estimations, who's geometry might come in one form or another (translated, rotated or mirrored). The default shape atlas might estimate the following shapes:

  • concave quadrilateral
  • equilateral hexagon
  • equilateral pentagon
  • equilateral triangle
  • golder-ratio triangle
  • rhombus
  • silver-ratio triangle
  • spark
  • star
  • trapezoid

Default atlas can be viewed in this file.

In addition, there are few base shapes which might be estimated regardless of the atlas that we provide:

  • circle
  • hexagon
  • octagon
  • open polygon
  • pentagon
  • polygon
  • rectangle
  • square
  • triangle
  • vector
  • vector

example

By default, specified atlas shapes will be considered to be a closed polygon:

import shapeit from 'shapeit'

const shapethat = shapeit.new({
  atlas: {
    parallelogram: [
      [1, 0],
      [5, 0],
      [4, 2],
      [0, 2],
      [1, 0],
    ]
  }
})

const uglyParallelogram = [
  [0.9 , 0.1 ],
  [3   , 0.2 ],
  [5.1 , -0.1],
  [4.6 , 0.9 ],
  [4.2 , 2.2 ],
  [2.1 , 2   ],
  [-0.1, 1.9 ],
  [0.4 , 1.1 ],
  [1.2 , -0.1],
]

const prettyParallelogram = shapethat(uglyParallelogram)

assert(prettyParallelogram, [[Number, Number]])
assert(prettyParallelogram.closed, true)
assert(prettyParallelogram.name, 'parallelogram')

If we would like to specify an open polygon, instead of providing an object with an extra closed boolean field, and the vertexes will be specified under the vertexes field:

import shapeit from 'shapeit'

const shapethat = shapeit.new({
  atlas: {
    caret: {
      closed: false,
      vertices: [
        [-1, 0],
        [0 , 1],
        [1 , 0],
      ]
    }
  }
})

const uglyCaret = [
  [-1.1, 0.1  ],
  [-0.1, 0.89 ],
  [1.2 , -0.05],
]

const prettyCaret = shapethat(uglyCaret)

assert(prettyCaret, [[Number, Number]])
assert(prettyCaret.closed, false)
assert(prettyCaret.name, 'caret')

threshold constants

Although many times unnecessary and even dangerous, we can modify the threshold constants. Each threshold is used to detect a specific feature in the given shape so we can determine the final result and fix it accordingly. Here's a list of all thresholds followed by a description of their role:

  • circleReductionAngle - When trying to match the given shape with a circle, all its angles whose values are greater than this one will be reduced. A higher value will result in a higher probability for a circle match. Ranges between 0 and π and defaults to 0.6.
  • circleClosureDistance - A given open shape might be considered as a circle only if the distance between the last vertex and one of the vectors is shorter than this value, which means that a higher value will more likely result in a circle and not an open polygon. Ranges between 0 and ∞ and defaults to 100.
  • normalDistance - A given open shape might be automatically closed and matched with one of the shapes in the atlas only if the distance between the last vertex and one of the vectors is shorter than this value. Ranges between 0 and ∞ and defaults to 90.
  • radiusesStdRatio - Used to indicate how evenly distributed are all the radiuses by checking the ratio of their standard deviation with the average radius size. A lower value is more likely to match the given shape with a circle. Ranges between 0 and 1 and defaults to 0.18.
  • minPolygonArea - An intersection between 2 vectors will be considered one that forms a polygon only if its area is bigger than this value, which means that intersections that trap a small area won't be considered as ones that form a polygon and won't be taken into account in our calculations. Ranges between 0 and ∞ and defaults to 300.
  • minShapeScore - The minimum score for a match with one of the shapes in the atlas to be considered as a successful one. A higher value will result in more shapes that are likely to be matched. Ranges between 0 and 1 and defaults to 0.83.
  • minSquareScore - The minimum score that will gratify a square match, which means that a lower score will more likely match a given shape with a square. Ranges between 0 and 1 and defaults to 0.85.
  • vectorsReductionAngle - 2 vectors will be reduced into a single vector if the angle between them is lower than this value, otherwise they will be considered as 2 vectors which form a corner. A higher value will reduce more corners and will result in straight lines. Ranges between 0 and π and defaults to 0.3.

Default thresholds can be viewed in this file.

example

import shapeit from 'shapeit'

// Circles are more likely to be detected with these thresholds
const shapethat = shapeit.new({
  thresholds: {
    circleReductionAngle: 0.7,
    circleClosureDistance: 120,
  }
})

output options

The output shape can be configured upfront by specifying its output options. The output options are optional and may contain the following fields:

  • rectRotationProduct - If the output shape is a rectangle, its angle will be rounded to the nearest multiplication of this value. Ranges between 0 and 2π and defaults to π / 8.
  • vectorRotationProduct - If the output shape is a vector, its angle will be rounded to the nearest multiplication of this value. Ranges between 0 and 2π and defaults to π / 16.

Default output options can be viewed in this file.

example

import shapeit from 'shapeit'

// Will result in vertical or horizontal rectangles and vectors only
const shapethat = shapeit.new({
  output: {
    rectRotationProduct: Math.PI / 2,
    vectorRotationProduct: Math.PI / 2,
  }
})

Download

The source is available for download from GitHub. Alternatively, you can install using Node Package Manager (npm):

npm install shapeit