Socket
Socket
Sign inDemoInstall

@jscad/modeling

Package Overview
Dependencies
Maintainers
2
Versions
37
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@jscad/modeling - npm Package Compare versions

Comparing version 2.0.0-alpha.5 to 2.0.0-alpha.6

12

CHANGELOG.md

@@ -6,2 +6,14 @@ # Change Log

# [2.0.0-alpha.6](https://github.com/jscad/openjscad.org/compare/@jscad/modeling@2.0.0-alpha.5...@jscad/modeling@2.0.0-alpha.6) (2020-10-11)
### Bug Fixes
* **all:** V2 : several fixes for modeling ([#705](https://github.com/jscad/openjscad.org/issues/705)) ([62017a4](https://github.com/jscad/openjscad.org/commit/62017a41214169d6e000f1e0c11aaefdd68e1097))
* **core:** Remove connectors from public api ([#703](https://github.com/jscad/openjscad.org/issues/703)) ([a3bf8a4](https://github.com/jscad/openjscad.org/commit/a3bf8a42e7ccf2204351da4a4acff55c2d6acad6))
# [2.0.0-alpha.5](https://github.com/jscad/openjscad.org/compare/@jscad/modeling@2.0.0-alpha.4...@jscad/modeling@2.0.0-alpha.5) (2020-09-29)

@@ -8,0 +20,0 @@

9

package.json
{
"name": "@jscad/modeling",
"version": "2.0.0-alpha.5",
"version": "2.0.0-alpha.6",
"description": "Constructive Solid Geometry (CSG) Library",

@@ -8,2 +8,3 @@ "repository": "https://github.com/jscad/openjscad.org",

"scripts": {
"build": "browserify src/index.js -o dist/modeling.js -g uglifyify --standalone modeling",
"coverage": "nyc --all --reporter=html --reporter=text npm test",

@@ -58,5 +59,7 @@ "test": "ava 'src/**/*.test.js' --verbose --timeout 2m",

"ava": "3.10.0",
"conventional-changelog-cli": "^1.3.4"
"browserify": "16.5.1",
"nyc": "15.1.0",
"uglifyify": "5.0.2"
},
"gitHead": "0d21a54b5e3435867420e4d8c96a23893db28ef2"
"gitHead": "a08ba28184627770c74c3dbfa25fb181b8459b0c"
}

@@ -48,3 +48,3 @@ /**

let firstPointType = null
points.forEach(point => {
points.forEach((point) => {
let pType = ''

@@ -54,3 +54,3 @@ if (Number.isFinite(point)) {

} else if (Array.isArray(point)) {
point.forEach(val => {
point.forEach((val) => {
if (!Number.isFinite(val)) throw new Error('Bezier point values must all be numbers.')

@@ -57,0 +57,0 @@ })

@@ -26,3 +26,3 @@ /**

const singleDimensionPoints = []
for (var j = 0; j < bezier.points.length; j++) {
for (let j = 0; j < bezier.points.length; j++) {
singleDimensionPoints.push(bezier.points[j][i])

@@ -29,0 +29,0 @@ }

@@ -18,12 +18,16 @@ const vec2 = require('../../maths/vec2')

}
if (points.length < 3) {
let length = points.length
if (length < 3) {
throw new Error('the given points must define a closed geometry with three or more points')
}
// adjust length if the given points are closed by the same point
if (vec2.equals(points[0], points[length - 1])) --length
const sides = []
let prevpoint = points[points.length - 1]
points.forEach((point) => {
let prevpoint = points[length - 1]
for (let i = 0; i < length; i++) {
const point = points[i]
sides.push([vec2.fromArray(prevpoint), vec2.fromArray(point)])
prevpoint = point
})
}
return create(sides)

@@ -30,0 +34,0 @@ }

@@ -12,2 +12,5 @@ const test = require('ava')

t.deepEqual(fromPoints(points), expected)
const points2 = [[0, 0], [1, 0], [0, 1], [0, 0]]
t.deepEqual(fromPoints(points2), expected)
})

@@ -14,0 +17,0 @@

const test = require('ava')
const { fromCompactBinary, toCompactBinary, create, fromPoints, equals } = require('./index')
const { fromCompactBinary, toCompactBinary, create, fromPoints } = require('./index')

@@ -5,0 +5,0 @@ test('toCompactBinary: converts geom3 (default)', (t) => {

@@ -10,6 +10,4 @@ /**

const measureArea = (polygon) => {
return area(polygon.vertices)
}
const measureArea = (polygon) => area(polygon.vertices)
module.exports = measureArea
module.exports = {
colors: require('./colors'),
connectors: require('./connectors'),
curves: require('./curves'),

@@ -5,0 +4,0 @@ geometries: require('./geometries'),

@@ -21,3 +21,3 @@ const test = require('ava')

const int4 = intersectPointOfLines(line4, line3)
// FIXME BUG?? t.true(compareVectors(int4, [Infinity, -Infinity]))
t.true(compareVectors(int4, [Infinity, -Infinity]))

@@ -24,0 +24,0 @@ // intersecting lines

@@ -7,4 +7,2 @@ const test = require('ava')

const { compareVectors } = require('../../../test/helpers/index')
test('mat4: isMirroring() should determine correctlly', (t) => {

@@ -11,0 +9,0 @@ let matrix = identity()

@@ -5,4 +5,2 @@ const test = require('ava')

const { compareVectors } = require('../../../test/helpers/index')
test('vec4: dot() should return proper values', (t) => {

@@ -9,0 +7,0 @@ const vecA = fromValues(1, 2, 3, 4)

@@ -1,3 +0,1 @@

const vec3 = require('../../maths/vec3')
const geom3 = require('../../geometries/geom3')

@@ -4,0 +2,0 @@ const poly3 = require('../../geometries/poly3')

@@ -36,3 +36,3 @@ const test = require('ava')

test('offset: offsetting a bent line produces expected geometry', (t) => {
const points = [[0, 0], [0, 10], [10, 10]]
const points = [[0, 0], [0, 5], [0, 10], [5, 10], [10, 10]]
const linePath2 = path2.fromPoints({ closed: false }, points)

@@ -43,3 +43,3 @@

let offsetPoints = path2.toPoints(offsetLinePath2)
t.is(offsetPoints.length, 3)
t.is(offsetPoints.length, 5)
let boundingBox = measureBoundingBox(offsetLinePath2)

@@ -51,3 +51,3 @@ t.true(comparePoints(boundingBox, [[2, 0, 0], [10, 8, 0]]), 'Unexpected bounding box: ' + JSON.stringify(boundingBox))

offsetPoints = path2.toPoints(offsetLinePath2)
t.is(offsetPoints.length, 5) // obtuse angles produce 3 points, even in edge offsets
t.is(offsetPoints.length, 7)
boundingBox = measureBoundingBox(offsetLinePath2)

@@ -57,12 +57,11 @@ t.true(comparePoints(boundingBox, [[-2, 0, 0], [10, 12, 0]]), 'Unexpected bounding box: ' + JSON.stringify(boundingBox))

// TODO This test fails, since two parallel lines that connect are not considered to intersect, causing it to try and create impossible geometry.
// test('offset: offsetting a 2 segment straight line produces expected geometry', (t) => {
// const points = [[0, 0], [0, 5], [0, 10]]
// const linePath2 = path2.fromPoints({ closed: false }, points)
// const offsetLinePath2 = offset({ delta: 2, corners: 'edge', segments: 8 }, linePath2)
// const offsetPoints = path2.toPoints(offsetLinePath2)
// t.is(offsetPoints.length, 3)
// const boundingBox = measureBoundingBox(offsetLinePath2)
// t.true(comparePoints(boundingBox, [[2, 0, 0], [2, 10, 0]]), 'Unexpected bounding box: ' + JSON.stringify(boundingBox))
// })
test('offset: offsetting a 2 segment straight line produces expected geometry', (t) => {
const points = [[0, 0], [0, 5], [0, 10]]
const linePath2 = path2.fromPoints({ closed: false }, points)
const offsetLinePath2 = offset({ delta: 2, corners: 'edge', segments: 8 }, linePath2)
const offsetPoints = path2.toPoints(offsetLinePath2)
t.is(offsetPoints.length, 3)
const boundingBox = measureBoundingBox(offsetLinePath2)
t.true(comparePoints(boundingBox, [[2, 0, 0], [2, 10, 0]]), 'Unexpected bounding box: ' + JSON.stringify(boundingBox))
})

@@ -69,0 +68,0 @@ test('offset (corners: chamfer): offset of a path2 produces expected offset path2', (t) => {

@@ -100,6 +100,13 @@ const { EPS } = require('../../maths/constants')

const ip = line2.intersectPointOfLines(line0, line1)
const p0 = corner.s0[1]
let i = newPoints.findIndex((point) => vec2.equals(p0, point))
i = (i + 1) % newPoints.length
newPoints.splice(i, 0, ip)
if (Number.isFinite(ip[0]) && Number.isFinite(ip[1])) {
const p0 = corner.s0[1]
let i = newPoints.findIndex((point) => vec2.equals(p0, point))
i = (i + 1) % newPoints.length
newPoints.splice(i, 0, ip)
} else {
// paralell segments, drop one
const p0 = corner.s1[0]
const i = newPoints.findIndex((point) => vec2.equals(p0, point))
newPoints.splice(i, 1)
}
})

@@ -124,18 +131,25 @@ }

// generate the segments
cornersegments = Math.floor(segments * (Math.abs(rotation) / (2 * Math.PI)))
const step = rotation / cornersegments
const start = vec2.angle(vec2.subtract(corner.s0[1], corner.c))
const cornerpoints = []
for (let i = 1; i < cornersegments; i++) {
const radians = start + (step * i)
const point = vec2.add(corner.c, vec2.scale(delta, vec2.fromAngleRadians(radians)))
cornerpoints.push(point)
if (rotation !== 0.0) {
// generate the segments
cornersegments = Math.floor(segments * (Math.abs(rotation) / (2 * Math.PI)))
const step = rotation / cornersegments
const start = vec2.angle(vec2.subtract(corner.s0[1], corner.c))
const cornerpoints = []
for (let i = 1; i < cornersegments; i++) {
const radians = start + (step * i)
const point = vec2.add(corner.c, vec2.scale(delta, vec2.fromAngleRadians(radians)))
cornerpoints.push(point)
}
if (cornerpoints.length > 0) {
const p0 = corner.s0[1]
let i = newPoints.findIndex((point) => vec2.equals(p0, point))
i = (i + 1) % newPoints.length
newPoints.splice(i, 0, ...cornerpoints)
}
} else {
// paralell segments, drop one
const p0 = corner.s1[0]
const i = newPoints.findIndex((point) => vec2.equals(p0, point))
newPoints.splice(i, 1)
}
if (cornerpoints.length > 0) {
const p0 = corner.s0[1]
let i = newPoints.findIndex((point) => vec2.equals(p0, point))
i = (i + 1) % newPoints.length
newPoints.splice(i, 0, ...cornerpoints)
}
})

@@ -142,0 +156,0 @@ }

@@ -9,7 +9,7 @@ const flatten = require('../../utils/flatten')

options.modes = padArrayToLength(options.modes, 'none', 3)
if (options.modes.filter(mode => ['center', 'max', 'min', 'none'].includes(mode)).length !== 3) throw new Error('align(): all modes must be one of "center", "max" or "min"')
if (options.modes.filter((mode) => ['center', 'max', 'min', 'none'].includes(mode)).length !== 3) throw new Error('align(): all modes must be one of "center", "max" or "min"')
if (!Array.isArray(options.alignTo) || options.alignTo.length > 3) throw new Error('align(): alignTo must be an array of length <= 3')
options.alignTo = padArrayToLength(options.alignTo, 0, 3)
if (options.alignTo.filter(alignVal => (Number.isFinite(alignVal) || alignVal == null)).length !== 3) throw new Error('align(): all alignTo values must be a number, or null.')
if (options.alignTo.filter((alignVal) => (Number.isFinite(alignVal) || alignVal == null)).length !== 3) throw new Error('align(): all alignTo values must be a number, or null.')

@@ -78,3 +78,3 @@ if (typeof options.grouped !== 'boolean') throw new Error('align(): grouped must be a boolean value.')

if (alignTo.filter(val => val == null).length) {
if (alignTo.filter((val) => val == null).length) {
const bounds = measureAggregateBoundingBox(geometries)

@@ -86,5 +86,3 @@ alignTo = populateAlignToFromBounds(alignTo, modes, bounds)

} else {
geometries = geometries.map(geometry => {
return alignGeometries(geometry, modes, alignTo)
})
geometries = geometries.map((geometry) => alignGeometries(geometry, modes, alignTo))
}

@@ -91,0 +89,0 @@ return geometries.length === 1 ? geometries[0] : geometries

@@ -64,6 +64,24 @@ const flatten = require('../../utils/flatten')

/**
* Center the given geometries about the X axis.
* @param {...Object} geometries - the geometries to center
* @return {Object|Array} the centered geometry, or a list of centered geometry
* @alias module:modeling/transforms.centerX
*/
const centerX = (...objects) => center({ axes: [true, false, false] }, objects)
/**
* Center the given geometries about the Y axis.
* @param {...Object} geometries - the geometries to center
* @return {Object|Array} the centered geometry, or a list of centered geometry
* @alias module:modeling/transforms.centerY
*/
const centerY = (...objects) => center({ axes: [false, true, false] }, objects)
/**
* Center the given geometries about the Z axis.
* @param {...Object} geometries - the geometries to center
* @return {Object|Array} the centered geometry, or a list of centered geometry
* @alias module:modeling/transforms.centerZ
*/
const centerZ = (...objects) => center({ axes: [false, false, true] }, objects)

@@ -70,0 +88,0 @@

@@ -11,2 +11,4 @@ const ellipse = require('./ellipse')

* @param {Number} [options.radius=1] - radius of circle
* @param {Number} [options.startAngle=0] - start angle of circle, in radians
* @param {Number} [options.endAngle=(Math.PI * 2)] - end angle of circle, in radians
* @param {Number} [options.segments=32] - number of segments to create per full rotation

@@ -22,5 +24,7 @@ * @returns {geom2} new 2D geometry

radius: 1,
startAngle: 0,
endAngle: (Math.PI * 2),
segments: 32
}
let { center, radius, segments } = Object.assign({}, defaults, options)
let { center, radius, startAngle, endAngle, segments } = Object.assign({}, defaults, options)

@@ -31,5 +35,5 @@ if (!isGT(radius, 0)) throw new Error('radius must be greater than zero')

return ellipse({ center, radius, segments })
return ellipse({ center, radius, startAngle, endAngle, segments })
}
module.exports = circle

@@ -83,2 +83,40 @@ const test = require('ava')

// test startAngle
geometry = circle({ radius: 3.5, startAngle: Math.PI / 2, segments: 16 })
pts = geom2.toPoints(geometry)
exp = [
[2.143131898507868e-16, 3.5],
[-1.339392013277814, 3.2335783637895035],
[-2.474873734152916, 2.4748737341529163],
[-3.2335783637895035, 1.3393920132778145],
[-3.5, 4.286263797015736e-16],
[-3.233578363789504, -1.3393920132778139],
[-2.474873734152917, -2.474873734152916],
[-1.339392013277816, -3.233578363789503],
[-6.429395695523604e-16, -3.5],
[1.339392013277815, -3.233578363789503],
[2.474873734152916, -2.474873734152917],
[3.233578363789503, -1.3393920132778163],
[3.5, -8.572527594031472e-16],
[0, 0]
]
t.deepEqual(pts.length, 14)
t.true(comparePoints(pts, exp))
// test endAngle
geometry = circle({ radius: 3.5, endAngle: Math.PI / 2, segments: 16 })
pts = geom2.toPoints(geometry)
exp = [
[3.5, 0],
[3.2335783637895035, 1.3393920132778143],
[2.4748737341529163, 2.474873734152916],
[1.3393920132778145, 3.2335783637895035],
[2.143131898507868e-16, 3.5],
[0, 0]
]
t.deepEqual(pts.length, 6)
t.true(comparePoints(pts, exp))
// test segments

@@ -85,0 +123,0 @@ geometry = circle({ radius: 3.5, segments: 5 })

@@ -66,3 +66,3 @@ const { EPS } = require('../maths/constants')

(2 * minradius * minradius))
if (rotation < minangle) throw new Error('startAngle and endAngle to not define a significant rotation')
if (rotation < minangle) throw new Error('startAngle and endAngle do not define a significant rotation')

@@ -69,0 +69,0 @@ const slices = Math.floor(segments * (rotation / (Math.PI * 2)))

@@ -0,1 +1,3 @@

const { EPS } = require('../maths/constants')
const vec2 = require('../maths/vec2')

@@ -13,2 +15,4 @@

* @param {Array} [options.radius=[1,1]] - radius of ellipse, along X and Y
* @param {Number} [options.startAngle=0] - start angle of ellipse, in radians
* @param {Number} [options.endAngle=(Math.PI * 2)] - end angle of ellipse, in radians
* @param {Number} [options.segments=32] - number of segments to create per full rotation

@@ -24,5 +28,7 @@ * @returns {geom2} new 2D geometry

radius: [1, 1],
startAngle: 0,
endAngle: (Math.PI * 2),
segments: 32
}
const { center, radius, segments } = Object.assign({}, defaults, options)
let { center, radius, startAngle, endAngle, segments } = Object.assign({}, defaults, options)

@@ -32,13 +38,36 @@ if (!isNumberArray(center, 2)) throw new Error('center must be an array of X and Y values')

if (!radius.every((n) => n > 0)) throw new Error('radius values must be greater than zero')
if (!isGTE(startAngle, 0)) throw new Error('startAngle must be positive')
if (!isGTE(endAngle, 0)) throw new Error('endAngle must be positive')
if (!isGTE(segments, 3)) throw new Error('segments must be three or more')
startAngle = startAngle % (Math.PI * 2)
endAngle = endAngle % (Math.PI * 2)
let rotation = (Math.PI * 2)
if (startAngle < endAngle) {
rotation = endAngle - startAngle
}
if (startAngle > endAngle) {
rotation = endAngle + ((Math.PI * 2) - startAngle)
}
const minradius = Math.min(radius[0], radius[1])
const minangle = Math.acos(((minradius * minradius) + (minradius * minradius) - (EPS * EPS)) /
(2 * minradius * minradius))
if (rotation < minangle) throw new Error('startAngle and endAngle do not define a significant rotation')
segments = Math.floor(segments * (rotation / (Math.PI * 2)))
const centerv = vec2.fromArray(center)
const step = 2 * Math.PI / segments // radians
const step = rotation / segments // radians per segment
const points = []
segments = (rotation < Math.PI * 2) ? segments + 1 : segments
for (let i = 0; i < segments; i++) {
const point = vec2.fromValues(radius[0] * Math.cos(step * i), radius[1] * Math.sin(step * i))
const angle = (step * i) + startAngle
const point = vec2.fromValues(radius[0] * Math.cos(angle), radius[1] * Math.sin(angle))
vec2.add(point, centerv, point)
points.push(point)
}
if (rotation < Math.PI * 2) points.push(centerv)
return geom2.fromPoints(points)

@@ -45,0 +74,0 @@ }

@@ -83,2 +83,40 @@ const test = require('ava')

// test startAngle
geometry = ellipse({ radius: [3, 5], startAngle: Math.PI / 2, segments: 16 })
obs = geom2.toPoints(geometry)
exp = [
[1.8369701987210297e-16, 5],
[-1.1480502970952693, 4.619397662556434],
[-2.1213203435596424, 3.5355339059327378],
[-2.77163859753386, 1.9134171618254494],
[-3, 6.123233995736766e-16],
[-2.7716385975338604, -1.9134171618254483],
[-2.121320343559643, -3.5355339059327373],
[-1.148050297095271, -4.619397662556432],
[-5.51091059616309e-16, -5],
[1.14805029709527, -4.619397662556433],
[2.121320343559642, -3.5355339059327386],
[2.7716385975338595, -1.913417161825452],
[3, -1.2246467991473533e-15],
[0, 0]
]
t.deepEqual(obs.length, 14)
t.true(comparePoints(obs, exp))
// test endAngle
geometry = ellipse({ radius: [3, 5], endAngle: Math.PI / 2, segments: 16 })
obs = geom2.toPoints(geometry)
exp = [
[3, 0],
[2.77163859753386, 1.913417161825449],
[2.121320343559643, 3.5355339059327373],
[1.1480502970952695, 4.619397662556434],
[1.8369701987210297e-16, 5],
[0, 0]
]
t.deepEqual(obs.length, 6)
t.true(comparePoints(obs, exp))
// test segments

@@ -85,0 +123,0 @@ geometry = ellipse({ segments: 72 })

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc