Skip to content

Instantly share code, notes, and snippets.

@hrgdavor
Last active December 8, 2020 09:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hrgdavor/d122fdba873a2ba796273ec7c0d4bc89 to your computer and use it in GitHub Desktop.
Save hrgdavor/d122fdba873a2ba796273ec7c0d4bc89 to your computer and use it in GitHub Desktop.
towel hanger
/*
.\_dev_build\watch_dev.bat -l .\_useful\towel_hnager.jscad
*/
var _parameters = [
{name:'pipeDiameter',caption:'Pipe diameter', type:'int', initial:23},
{name:'pipeDistance',caption:'Pipe distance', type:'int', initial:36},
{name:'width',caption:'width', type:'int', initial:10},
{name:'thick',caption:'Thickness', type:'float', initial:3.5},
{name:'preview',caption:'Preview', type:'checkbox', checked:false},
];
var funcs = new Map();
var outerRad = 202;
var outerRad = 202;
var wall = 1.5;
var bottom = 1;
funcs.base = function({pipeDiameter, pipeDistance, width=10, thick=3, preview=false}){
var r = pipeDiameter/2 + thick/2
var ret = []
var cx = 0, cy = pipeDistance;
if(preview){
ret.push(colors.colorize([1,0,0,0.7],bottomCylinder({radius:pipeDiameter/2, height:width, ty:pipeDistance})))
ret.push(colors.colorize([1,0,0,0.7],bottomCylinder({radius:pipeDiameter/2, height:width})))
}
var p = new P2DPoints(...rPointD(r,190,cx,cy))
for(var a = 185; a>-41; a-=5){
p.at(...rPointD(r,a,cx,cy))
}
p.at(...rPointD(r-1,135))
ret.push( p.build(width,{w:thick/2, closed:false, preview:0}))
var p = new P2DPoints(r, pipeDistance)
p.yTo(0)
// ret.push( p.build(width,{w:thick/2, closed:false, preview:0}))
var startX = r+thick/2 - thick;
p = new P2DPoints(startX,0).x(thick)
p.y(pipeDistance-25)
p.add(PointUtils.arc,{segments:8, y:2, mirror:false})
p.m(8,13)
p.add(PointUtils.arc,{segments:8, y:0.5, mirror:true})
p.m(7,7)
p.add(PointUtils.arc,{segments:4, y:1, mirror:true})
p.m(1,8)
p.add(PointUtils.arc,{segments:4, y:0.5, mirror:true})
p.m(-4,5)
p.x(-1)
p.add(PointUtils.arc,{segments:4, y:0.5, mirror:false})
p.m(1.5,-8)
p.add(PointUtils.arc,{segments:8, y:6, mirror:false})
p.at(startX+thick,pipeDistance-1).yTo(pipeDistance).x(-thick)
p.at(...rPointD(r,-30,cx,cy))
p.at(...rPointD(r,-45,cx,cy))
p.at(...rPointD(r,-60,cx,cy))
p.at(...rPointD(r+thick/2+1.5,-60,cx,cy))
p.add(PointUtils.arc,{segments:8, y:1.5, mirror:false})
p.xToMy(startX,-2)
ret.push(p.build(width,{preview:0, reverse:false}))
// return p.build(width,{preview:0, reverse:false})
// p = new P2DPoints(r+16,29)
// p.m(-1,3)
// ret.push(p.build(width,{w:thick/2, closed:false, preview:0}))
var r2 = 6+thick;
ret.push(bottomCylinderElliptic({radius:r2, wall:thick, height: width, sliceD:[180,0], tx:startX+r2}));
// ret.push(p.build(width,{w:thick/2, closed:false, preview:0}))
p = new P2DPoints()
p.add(PointUtils.arc,{segments:2, y:1, mirror:true})
p.m(-thick,5).x(-1)
p.add(PointUtils.arc,{segments:2, y:0.5})
p.at(-thick,0)
ret.push(p.build(width,{preview:0, reverse:false, tx:startX+r2*2}))
return preview ? ret : union(ret);
}
// bottomCube cornerCube bottomCylinder makeText size length P2DPoints
// translate rotate difference cylinderElliptic bottomCylinderElliptic startRadius
function getParameterDefinitions() {
let keys = Object.keys(funcs);
if(keys.length > 1){
_parameters.push({
name:'piece',
caption:'Piece', type:'choice',
keys
});
}
return _parameters;
}
function main(params){
let keys = Object.keys(funcs);
var piece = params.piece || keys[0];
if(!funcs[piece]){ piece = keys[0]}
return funcs[piece](params || {});
}
module.exports = {main, getParameterDefinitions}
const jscad = require('@jscad/modeling')
const { connectors, geometry, math, primitives, text, utils, booleans, expansions, extrusions, hulls, measurements, transforms, colors } = jscad
const { cuboid, sphere, cylinder, circle, star,cylinderElliptic } = jscad.primitives
const { translate, scale, center } = transforms
const { union, subtract, intersect } = booleans
const difference = subtract;
const { vectorText } = jscad.text
const rectangular_extrude = jscad.extrusions.extrudeRectangular;
const linear_extrude = jscad.extrusions.extrudeLinear;
const { mat4 } = jscad.maths
const { geom2, geom3, path2, poly2, poly3 } = jscad.geometries
const { extrudeFromSlices, slice, extrudeLinear } = jscad.extrusions
const extrudeChamfer = ({baseSlice, h=10, cut=0, cutTop=0, cutBottom=0, tz=0, tx=0, ty=0}) => {
cutTop = cutTop || cut;
cutBottom = cutBottom || cut;
let levels = [];
if(cutBottom){
levels.push([0,-cutBottom]);
levels.push([cutBottom,0]);
}else{
levels.push([0,0]);
}
levels.push([h-cutTop-cutBottom,0]);
if(cutTop){
levels.push([cutTop, -cutTop]);
}
return extrudeLevels({levels, baseSlice, tz, tx, ty})
}
const extrudeLevels = ({levels, baseSlice, corners='edge', segments=16, tz=0, tx=0, ty=0}) => {
var h = 0;
return extrudeFromSlices({numberOfSlices:levels.length, callback:(progress, counter)=>{
var level = levels[counter];
h += level[0];
base = jscad.expansions.offset({delta:level[1], corners, segments},baseSlice);
// DIRTY FIX for what expand does to original geom
if(level[1] > 0){
if(corners == 'round'){
for(let i=0; i<segments-1; i++){
let tmp = base.sides.shift();
base.sides.push(tmp);
}
}else{
let tmp = base.sides.pop();
base.sides.unshift(tmp);
}
}
base = slice.fromSides(base.sides);
return slice.transform(mat4.fromTranslation([0, 0, h+tz]), base);
}});
}
const extrudeScaleLevels = ({levels, baseSlice, corners='edge', segments=16, tz=0, tx=0, ty=0}) => {
var h = 0;
baseSlice = slice.fromSides(geom2.toSides(baseSlice))
return extrudeFromSlices({numberOfSlices:levels.length, callback:(progress, counter)=>{
var level = levels[counter];
h += level[0];
var scaleX = scaleY = level[1];
if(level.length > 2) scaleY = level[2];
const scaleMatrix = mat4.fromScaling([scaleX, scaleY, 1])
const transformMatrix = mat4.fromTranslation([0, 0, h])
return slice.transform(mat4.multiply(scaleMatrix, transformMatrix), baseSlice)
}});
}
const roundTop = (base, {height=4, r1=0.2, r1Percent=0, rx=0.1, ry=0, segments=1}) => {
if(r1Percent) r1 = r1Percent * height;
ry = ry || rx;
// radius is for one side, and scale factor is for both
rx = rx*2;
ry = ry*2;
var numberOfSlices = 2 + segments;
var step = 1/(numberOfSlices-1);
var angleDelta = Math.PI / (segments) / 2 ;
var angleDelta2 = 180 / (segments) / 2 ;
var startH = height - r1;
var baseSlice = slice.fromSides(geom2.toSides(base))
return extrudeFromSlices({
numberOfSlices,
callback: (progress, counter, baseSlice) => {
var h = progress * height;
let scaleX = 1;
let scaleY = 1;
if(progress == 1){ // top slice (counter = numSlices-1)
scaleX = 1 - rx;
scaleY = 1 - ry;
}else if(progress == step){ // first top slice (counter = 1)
h = startH;
}else if(progress > step){ // curve (counter = 2,3,4...)
var angle = (counter -1) * angleDelta;
h = height - r1 + (Math.sin(angle) * r1);
scaleX = 1 - rx + (Math.cos(angle) * rx);
scaleY = 1 - rx + (Math.cos(angle) * ry);
}else{
// bottom slice (counter = 0)
}
const scaleMatrix = mat4.fromScaling([scaleX, scaleY, 1])
const transformMatrix = mat4.fromTranslation([0, 0, h])
return slice.transform(mat4.multiply(scaleMatrix, transformMatrix), baseSlice)
}
}, baseSlice)
}
function cylinderFromTo(p1,p2, radius){
const sqr = x=>x*x
let dx = p2[0] - p1[0]
let dy = p2[1] - p1[1]
let dz = p2[2] - p1[2]
let height = Math.sqrt( sqr(dx) + sqr(dy) + sqr(dz))
let obj = cylinder({radius, height})
if(dx || dy){
let dxy = Math.sqrt( sqr(dx) + sqr(dy))
let ay = Math.atan(dxy/dz) *(dx < 0 ? -1:1)
let az = Math.atan(dy/dx)
let ax = dz < 0 ? -Math.PI:0
obj = transforms.rotate([ax,ay,az], obj)
}
let mid = [p1[0]+dx/2,p1[1]+dy/2,p1[2]+dz/2]
return translate(mid, obj)
}
function rPointD(r, angle, tx=0, ty=0){
return rPoint(r, toRad(angle), tx, ty)
}
function rPoint(r, angle, tx=0, ty=0){
return [tx + r * Math.cos(angle), ty + r * Math.sin(angle)];
}
function elipsePoint(r1,r2, angle){
return [r1 * Math.cos(angle), r2 * Math.sin(angle)];
}
function elipsePointD(r1,r2, angle){
return elipsePoint(r1,r2, toRad(angle))
}
function elipseAngle(r1,r2, angle){
if(r1 == r2) return angle;
var point = elipsePoint(r1,r2, angle);
var f1 = [0,0];
var f2 = [0,0];
var f;
if(r1 > r2){
f = Math.sqrt(r1*r1 - r2*r2)
f1[0] -= f;
f2[0] += f;
}else{
f = Math.sqrt(r2*r2 - r1*r1)
f1[1] -= f;
f2[1] += f;
}
return ( pointAngle(f1,point) + pointAngle(f2,point) ) / 2;
}
function elipseAngleD(r1,r2, angle){
if(r1 == r2) return angle;
return toDeg( elipseAngle(r1,r2, toRad(angle)) )
}
function elipseAngleMoveD(r1,r2,tz,angle,...pieces){
return elipseAngleMove(r1,r2,tz,toRad(angle),...pieces)
}
function elipseAngleMove(r1,r2,tz,angle,...pieces){
var p = elipsePoint(r1,r2,angle)
var angle = elipseAngle(r1,r2,angle)
return translate([...p,tz], transforms.rotate([0,0,angle],...pieces))
}
function pointAngle(p1, p2){
return Math.atan2(p2[1] - p1[1], p2[0] - p1[0])
}
function pointAngleD(p1, p2){
return toDeg(pointAngle(p1, p2))
}
function toRad(d){return d/180*Math.PI;}
function toDeg(r){return r*180/Math.PI;}
const _rMagnet = 2.1;
const _hMagnet = 2.9;
function rotateD(angles, ...parts){
return transforms.rotate(angles.map(toRad),...parts);
}
const _m5_screw = 2.6;
const _m5_nut = 4.6;
const _m5_nut_h = 3.9;
function reduceWidth(r, reduce){
var ret = [...r]
ret[0] = r[0] - reduce
ret[1] = r[1] - reduce
return ret;
}
function bottomCube(options){
options.center = dirAlign(options.align || 'T', options.size, [0,0,options.bottom || 0])
var piece = cuboid(options)
if(options.wall){
var {topWall = 0, bottomWall = 0} = options
options.size = reduceWidth(options.size, options.wall*2)// need to reduce double, one for each side
options.size[2] -= topWall + bottomWall
options.center[2] += bottomWall - (bottomWall + topWall) / 2
piece = subtract(piece, cuboid(options))
}
if(options.holes) piece = subtract(piece, translate(options.center,...options.holes))
return dirRotateMove(options, piece)[0];
}
function bottomCylinder(options){
var r2 = options.radius*2
options.center = dirAlign(options.align || 'T', [r2,r2,options.height], [0,0,options.bottom || 0])
var piece = cylinder(options)
if(options.wall){
var {topWall = 0, bottomWall = 0} = options
options.height -= topWall + bottomWall
options.radius -= options.wall
options.center[2] += bottomWall - (bottomWall + topWall) / 2
piece = subtract(piece, cylinder(options))
}
if(options.holes) piece = subtract(piece, ...options.holes)
return dirRotateMove(options, piece)[0];
}
function bottomCylinderElliptic(options){
var {radius} = options
const toArray = val=>val instanceof Array ? val:[val,val]
if(radius) options.startRadius = [radius,radius]
options.startRadius = toArray(options.startRadius)
var {startRadius} = options
if(!options.endRadius) options.endRadius = startRadius;
options.endRadius = toArray(options.endRadius)
options.center = dirAlign(options.align || 'T', [startRadius[0]*2,startRadius[1]*2,options.height], [0,0,options.bottom || 0])
// options.center = [0,0,options.height/2+(options.bottom || 0)];
if(options.slice){
options.startAngle = options.slice[0]
options.endAngle = options.slice[1]
}
if(options.sliceD){
options.startAngle = toRad(options.sliceD[0])
options.endAngle = toRad(options.sliceD[1])
}
var piece = cylinderElliptic(options)
if(options.wall){
var {topWall = 0, bottomWall = 0} = options
options.height -= topWall + bottomWall
options.startRadius = reduceWidth(startRadius, options.wall)
options.endRadius = reduceWidth(options.endRadius, options.wall)
options.center[2] += bottomWall - (bottomWall + topWall) / 2
piece = subtract(piece, cylinderElliptic(options))
}
if(options.holes) piece = subtract(piece, ...options.holes)
return dirRotateMove(options, piece)[0];
}
function dirAlign(align='T',size=[1,1,1],center=[0,0,0]){
for(let i=0; i<align.length; i++){
var dir = align[i];
if(dir == 'T') center[2] += size[2]/2
if(dir == 'B') center[2] -= size[2]/2
if(dir == 'S') center[1] -= size[1]/2
if(dir == 'N') center[1] += size[1]/2
if(dir == 'E') center[0] += size[0]/2
if(dir == 'W') center[0] -= size[0]/2
}
return center;
}
function dirRotateMove(options,...elems){
var dirs = options.dir||'';
var rot = [0,0,0]
for(let i=0; i<dirs.length; i++){
var dir = dirs[i];
if(dir == 'B') rot = [180,0,0]
if(dir == 'S') rot = [90,0,0]
if(dir == 'N') rot = [-90,0,0]
if(dir == 'E') rot = [0,90,0]
if(dir == 'W') rot = [0,-90,0]
if(dir == 'Y') rot[1] += 90
if(dir == 'y') rot[1] -= 90
if(dir == 'X') rot[0] += 90
if(dir == 'x') rot[0] -= 90
if(dir == 'Z') rot[2] += 90
if(dir == 'z') rot[2] -= 90
}
elems = [rotateD(rot ,...elems)]
if(options.tx || options.ty || options.tz)
elems = [translate([options.tx || 0, options.ty || 0, options.tz || 0 ], ...elems)];
return elems;
}
function magnetHole({r=_rMagnet, h=_hMagnet, tz=0, hTol=0}={}){
return bottomCylinder({radius:r, height:h+hTol, tz})
}
function csgFromSegments (segments, {w=2, h=1}={}) {
return segments.map(segment => rectangular_extrude(segment, { w, h }) );
}
function makeText({text='A', height=10, w=2, h=1}={}) {
if (text === undefined || text.length === 0) return []
const lineSegments3D = []
const lineSegmentPointArrays = vectorText({ x: 0, y: 0, height, input: text }) // line segments for each character
lineSegmentPointArrays.forEach((segmentPoints) => { // process the line segment
const segmentShape = extrudeLinear(
{ height: h },
jscad.expansions.expand({ delta: w, corners: 'round', segments: 16 }, jscad.primitives.line(segmentPoints))
)
lineSegments3D.push(segmentShape)
})
const messageObject = center([true, true, false], union(lineSegments3D))
return messageObject;
}
function m5_nut({height=_m5_nut_h, radius=_m5_nut, segments=6, rTol=0, hTol=0, bottom=0, dir='T', align='T', tx=0, ty=0, tz=0}={}){
var options = {height, radius, segments, rTol, hTol, bottom, align, dir, tx, ty, tz}
options.radius = options.radius + options.rTol;
options.height = options.height + options.hTol;
return bottomCylinder(options);
}
function m5_screw({height=10, radius=_m5_screw, segments=32, rTol=0, hTol=0, bottom=0, dir='T', align='T', tx=0, ty=0, tz=0}={}){
var options = {height, radius, segments, rTol, hTol, bottom, dir, tx, ty, tz}
options.radius = options.radius + options.rTol;
options.height = options.height + options.hTol;
return bottomCylinder(options);
}
function m5_both({height=10, bottom=0, rTol1=0, rTol2=0, hTol=0, dir='T', align='T', tx=0, ty=0, tz=0}={}){
var r2 = _m5_nut*2
var size = [r2,r2,height] // size together
var nutHalf = _m5_nut_h/2;
var center = dirAlign(align,size, [0,0, bottom - height/2 + nutHalf])
var nut = cylinder({segments:6, radius:_m5_nut+rTol1, height:_m5_nut_h, center})
var center = dirAlign(align,size, [0,0, bottom +nutHalf])
var screw = cylinder({height:height- _m5_nut_h, radius:_m5_screw+rTol2, center})
return dirRotateMove({dir,tx,ty,tz},[nut, screw])
}
function P2DPoints(x=0, y=0){
this.pos = {x,y};
this.points = [[x,y]];
}
var proto = P2DPoints.prototype;
proto.add = function(shape,options={}){
this.points.push({shape,options});
return this;
}
proto.at = function(x=0,y=0){
this.points.push([this.pos.x = x, this.pos.y = y]);
return this;
}
proto.m = function(x=0, y=0){
return this.at(this.pos.x + x, this.pos.y + y);
}
proto.x = function(x=0){
return this.m(x, 0);
}
proto.y = function(y){
return this.m(0, y);
}
proto.xTo = function(x=0){
return this.at(x, this.pos.y);
}
proto.xToMy = function(x=0, y=0){
return this.at(x, this.pos.y+y);
}
proto.yTo = function(y=0){
return this.at(this.pos.x, y);
}
proto.mXyTo = function(x=0,y=0){
return this.at(this.pos.x+x, y);
}
proto.aRad = function(rad, r){
return this.m(r * Math.cos(rad), r * Math.sin(rad));
}
proto.aDeg = function(deg, r){
return this.aRad(deg/180 * Math.PI, r);
}
proto.xRad = function(rad, x){
return this.m(x, x * Math.sin(rad) / Math.cos(rad));
}
proto.xDeg = function(deg, x){
return this.xRad(deg/180 * Math.PI, x);
}
proto.yRad = function(rad, y){
return this.m(y * Math.cos(rad) / Math.sin(rad), y);
}
proto.yDeg = function(deg, y){
return this.xRad(deg/180 * Math.PI, y);
}
proto.calcPoints = function(){
this.points = this.buildPoints();
}
proto.mirrorX = function({a=1,b=0, m0=-1, m1=1}={}){
return this.mirrorY({a,b,m0,m1});
}
proto.mirrorY = function({a=0, b=1, m0=1, m1=-1}={}){
var points = this.points;
// remove start vertical
var p0 = points[0];
var p1 = points[1];
if(!p1.shape && p0[a] == p1[a]) points.shift();
// remove end vertical
var pEnd0 = points[points.length -1];
var pEnd1 = points[points.length -2];
if(!pEnd1.shape && pEnd0[a] == pEnd1[a]) points.pop();
var count = points.length;
for(var i=count-1; i>=0;i--){
var p = points[i];
if(p.shape){
points.push(p);
}else{
points.push([p[0]*m0, p[1]*m1]);
}
}
}
proto.buildPoints = function(){
var sqr = x=>x*x;
var ret = [];
var points = this.points;
const myFix2 = n=>parseFloat(n.toFixed(2))
const isEqPoint = (p1,p2)=> myFix2(p1[0]) == myFix2(p2[0]) && myFix2(p1[1]) == myFix2(p2[1]);
for(var i=0; i<points.length; i++){
var point = points[i];
if(point.shape){
var prev = points[i-1];
var next = points[i+1];
var {options, shape} = point;
var tx=0, ty=0, distance=0, rad=0;
var deltaX = next[0] - prev[0];
var deltaY = next[1] - prev[1];
distance = Math.sqrt(sqr(next[0] - prev[0]) + sqr(next[1] - prev[1]));
if(typeof shape == 'function') shape = shape(distance, options);
var toAdd = shape.buildPoints ? shape.buildPoints():shape;
var rad = Math.atan2(deltaY, deltaX);
if(options.mirror) PointUtils.scalePoints(toAdd,1,-1);
if(options.start != undefined) tx = options.start;
if(options.center || options.end != undefined){
var len = 0;
toAdd.forEach(p=>{if(p[0] > len) len = p[0]});
if(options.center){
tx = distance/2 - len/2 + (options.start || 0);
}
if(options.end != undefined){
tx = distance - len - options.end;
}
}
if(rad && tx) {
// use tx to calc ty before it is changed
ty = tx * Math.sin(rad)
tx = tx * Math.cos(rad)
}
if(rad) PointUtils.rotatePoints(toAdd, rad)
if(tx) PointUtils.translatePoints(toAdd,tx,ty);
var pStart = points[0];
//PointUtils.translatePoints(toAdd, prev[0]-pStart[0], prev[1]-pStart[1])
PointUtils.translatePoints(toAdd, prev[0], prev[1])
while(isEqPoint(prev,toAdd[0])) toAdd.shift();
while(isEqPoint(next,toAdd[toAdd.length-1])) toAdd.pop();
ret.push(...toAdd);
}else{
ret.push([...point])
}
}
while(isEqPoint(ret[0], ret[ret.length-1])) ret.pop();
return ret;
}
function myFix2(n){ return parseFloat(n.toFixed(2))}
proto.build = function(h=0, {preview=0, closed=true, tx=0, ty=0, sx=1,sy=1, w=0, reverse=true}={}){
var points = this.buildPoints()
if(reverse) points=points.reverse();
if(sx != 1 || sy != 1) PointUtils.scalePoints(points, sx,sy);
if(tx != 0 || ty != 0) PointUtils.translatePoints(points, tx,ty);
if(!preview) try{
var shape = path2.fromPoints({closed}, points)
if(w) return [extrusions.extrudeRectangular({size:w , height:h, closed}, closed ? shape : path2.fromPoints({closed:false},points))]
shape = geom2.fromPoints(points)
if(h) return [extrusions.extrudeLinear({height: h}, shape)]
return [shape];
}catch(e){
console.log(e.message,e);
}
preview = preview || 0.1;
var tmp = this.points.filter(p=>!p.shape);
var ret = [extrusions.extrudeRectangular({size:preview , height:preview, closed}, path2.fromPoints({closed},points))];
if(tmp.length != this.points.length){
ret.push(colors.colorize([1,1,0],translate([0,0,-preview], extrusions.extrudeRectangular({size:preview , height:preview}, path2.fromPoints({closed},tmp)))))
}
for(var i=0; i<points.length; i++){
var p = points[i];
ret.push(
colors.colorize([0,0,1],
translate([p[0],p[1],preview],
cylinder({radius:preview/2, height:preview})
)
)
);
}
return ret;
}
var PointUtils = {};
PointUtils.arc = function(len, {y=10, segments=4}){
var p = [];
var x = len/2;
var r = y + ((x*x - y*y)/2/y * (y > x ? 1:1));
var rad = Math.atan2(r-y, x)* (y > x ? 1:1);
console.log(rad);
var step = (Math.PI/2 - rad ) / segments;
p.push([x,y]);
for(var i=segments-1; i>=0; i--){
var y2 = r * Math.sin(rad+step*i);
var x2 = r * Math.cos(rad+step*i);
p.push([x+x2,y2-r+y]);
p.unshift([x-x2,y2-r+y]);
}
return p;
}
PointUtils.curve = function(len, {i=2, px=0.3, py=0.2, y=0}){
var sqr = x=>x*x
if(y) py = y/len;
var p = [];
var segments = 4;
var top = len*py;
var dx = len*px;
for(var i=0; i<segments; i++){
p.push([dx/segments*i, top-sqr(1/segments*(segments-i))*top])
}
p.push([len*px,top]);
var dx2 = len-dx;
for(var i=1; i<segments; i++){
p.push([dx+dx2/segments*i, top-sqr(1/segments*i)*top])
}
return p;
}
PointUtils.bump = function({d=2,w=2}={}){
return new P2DPoints(0,0).y(d).x(w).y(-d);
}
PointUtils.flipPoints = function(points){
points.forEach(p=>{
let tmp = p[0];
p[0] = p[1];
p[1] = tmp;
});
}
PointUtils.scalePoints = function(points, sx, sy){
if(sx == 1 && sy == 1) return;
points.forEach(p=>{
p[0] = p[0] * sx;
p[1] = p[1] * sy;
});
}
PointUtils.rotatePoints = function(points, rad){
if(rad == 0) return;
points.forEach(p=>{
var x = p[0], y=p[1];
p[0] = x * Math.cos(rad) - y * Math.sin(rad);
p[1] = y * Math.cos(rad) + x * Math.sin(rad);
});
}
PointUtils.translatePoints = function(points, tx, ty){
points.forEach(p=>{
p[0] = p[0] + tx;
p[1] = p[1] + ty;
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment