mirror of
https://github.com/BelfrySCAD/BOSL2.git
synced 2025-01-15 17:09:40 +00:00
Merge d4a8fdb6fe
into c442c5159a
This commit is contained in:
commit
6421a50229
6 changed files with 218 additions and 55 deletions
123
attachments.scad
123
attachments.scad
|
@ -4998,4 +4998,127 @@ function _canonical_edge(edge) =
|
|||
flip * edge;
|
||||
|
||||
|
||||
// Section: Attachable Descriptions for Operating on Attachables or Restoring a Previous State
|
||||
|
||||
// Function: parent()
|
||||
// Topics: Transforms, Attachments, Descriptions
|
||||
// See Also: restore()
|
||||
// Synopsis: Returns a description (transformation state and attachment geometry) of the parent
|
||||
// Usage:
|
||||
// PARENT() let( desc = parent() ) CHILDREN;
|
||||
// Usage: in development releases only
|
||||
// PARENT() { desc=parent(); CHILDREN; }
|
||||
// Description:
|
||||
// Returns a description of the closest attachable ancestor in the geometry tree, along with the current transformation. You can use this
|
||||
// description to create new objects based on the described object or perform computations based on the described object. You can also use it to
|
||||
// restore the context of the parent object and transformation state using {{restore()}}. Note that with OpenSCAD 2021.01 you need to use `let` for
|
||||
// this function to work, and the definition of the variable is scoped to the children of the let module.
|
||||
// (In development versions the use of let is no longer necessary.) Note that if OpenSCAD displays any warnings
|
||||
// related to transformation operations then the transformation that parent() returns is likely to be incorrect, even if OpenSCAD
|
||||
// continues to run and produces a valid result.
|
||||
function parent() =
|
||||
let(
|
||||
geom = default($parent_geom, attach_geom([0,0,0]))
|
||||
)
|
||||
[$transform, geom];
|
||||
|
||||
|
||||
// Module: restore()
|
||||
// Synopsis: Restores transformation state and attachment geometry from a description
|
||||
// SynTags: Trans
|
||||
// Topics: Transforms, Attachments, Descriptions
|
||||
// See Also: parent()
|
||||
// Usage:
|
||||
// restore([desc]) CHILDREN;
|
||||
// Description:
|
||||
// Restores the transformation and parent geometry contained in the specified description which you obtained with {{parent()}}.
|
||||
// If you don't give a description then restores the global world coordinate system with a zero size cuboid object as the parent.
|
||||
// Arguments:
|
||||
// desc = saved description to restore. Default: restore to world coordinates
|
||||
// Example(3D): The pink cube is a child of the green cube, but {{restore()}} restores the state to the yellow parent cube, so the pink cube attaches to the yellow cube
|
||||
// left(5) cuboid(10)
|
||||
// let(save_pt = parent())
|
||||
// attach(RIGHT,BOT) recolor("green") cuboid(3)
|
||||
// restore(save_pt)
|
||||
// attach(FWD,BOT) recolor("pink") cuboid(3);
|
||||
|
||||
module restore(desc)
|
||||
{
|
||||
req_children($children);
|
||||
if (is_undef(desc)){
|
||||
T = matrix_inverse($transform);
|
||||
$parent_geom = ["prismoid", [CTR, UP, 0]];
|
||||
multmatrix(T) children();
|
||||
}
|
||||
else{
|
||||
assert(!is_undef(desc) && is_list(desc) && len(desc)==2, "Invalid desc");
|
||||
T = linear_solve($transform, desc[0]);
|
||||
$parent_geom = desc[1];
|
||||
multmatrix(T) children();
|
||||
}
|
||||
}
|
||||
|
||||
// Function desc_point()
|
||||
// Synopsis: Computes the location in the current context of an anchor point from an attachable description
|
||||
// Topics: Descriptions, Attachments
|
||||
// See Also: parent(), desc_dist()
|
||||
// Usage:
|
||||
// point = desc_point(desc,[anchor]);
|
||||
// Description:
|
||||
// Computes the coordinates of the specified anchor point in the given description relative to the current transformation state.
|
||||
// Arguments:
|
||||
// desc = Description to use to get the point
|
||||
// anchor = Anchor point that you want to extract. Default: CENTER
|
||||
// Example(3D): In this example we translate away from the parent object and then compute points on that object. Note that with OpenSCAD 2021.01 you must use union() or alternatively place the pt1 and pt2 assignments in a let() statement. This is not necessary in development versions.
|
||||
// cuboid(10) let(desc=parent())
|
||||
// right(12) up(27)
|
||||
// union(){
|
||||
// pt1 = desc_point(desc,TOP+BACK+LEFT);
|
||||
// pt2 = desc_point(desc,TOP+FWD+RIGHT);
|
||||
// stroke([pt1,pt2,CENTER], closed=true, width=.5,color="red");
|
||||
// }
|
||||
// Example(3D): Here we compute the point on the parent so we can draw a line anchored on the child object that connects to a computed point on the parent
|
||||
// cuboid(10) let(desc=parent())
|
||||
// attach(FWD,BOT) cuboid([3,3,7])
|
||||
// attach(TOP+BACK+RIGHT, BOT)
|
||||
// stroke([[0,0,0], desc_point(desc,TOP+FWD+RIGHT)],width=.5,color="red");
|
||||
function desc_point(desc, anchor=CENTER) =
|
||||
is_undef(desc) ? linear_solve($transform, [0,0,0,0])
|
||||
: let(
|
||||
anch = _find_anchor(anchor, desc[1]),
|
||||
T = linear_solve($transform, desc[0])
|
||||
)
|
||||
apply(T, anch[1]);
|
||||
|
||||
|
||||
|
||||
// Function desc_dist()
|
||||
// Synopsis: Computes the distance between two points specified by attachable descriptions
|
||||
// Topics: Descriptions, Attachments
|
||||
// See Also: parent(), desc_point()
|
||||
// Usage:
|
||||
// dist = desc_dist(desc1,anchor1,desc2,anchor2);
|
||||
// dest = desc_dist(desc1=, desc2=, [anchor1=], [anchor2=]);
|
||||
// Description:
|
||||
// Computes the distance between two points specified using attachable descriptions and optional anchor
|
||||
// points. If you omit the anchor point(s) then the computation uses the CENTER anchor.
|
||||
// Example: Computes the distance between a point on each cube.
|
||||
// cuboid(10) let(desc=parent())
|
||||
// right(15) cuboid(10)
|
||||
// echo(desc_dist(parent(),TOP+RIGHT+BACK, desc, TOP+LEFT+FWD));
|
||||
|
||||
function desc_dist(desc1,anchor1=CENTER, desc2, anchor2=CENTER)=
|
||||
let(
|
||||
anch1 = _find_anchor(anchor1, desc1[1]),
|
||||
anch2 = _find_anchor(anchor2, desc2[1]),
|
||||
Tinv = matrix_inverse($transform),
|
||||
T1 = Tinv*desc1[0],
|
||||
T2 = Tinv*desc2[0],
|
||||
pt1 = apply(T1,anch1[1]),
|
||||
pt2 = apply(T2,anch2[1])
|
||||
)
|
||||
norm(pt1-pt2);
|
||||
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
|
@ -161,6 +161,8 @@ module color_overlaps(color="red") {
|
|||
%children();
|
||||
}
|
||||
|
||||
// Section: Setting Object Transparency
|
||||
|
||||
// Module: ghost()
|
||||
// Synopsis: Sets transparency for attachable children and their descendents.
|
||||
// SynTags: Trans
|
||||
|
|
|
@ -242,7 +242,7 @@ function nurbs_curve(control,degree,splinesteps,u, mult,weights,type="clamped",
|
|||
type=="open" ? assert(len(xknots)==len(control)+degree+1, str("For open spline, knot vector with multiplicity must have length ",
|
||||
len(control)+degree+1," but has length ", len(xknots)))
|
||||
xknots
|
||||
: type=="clamped" ? assert(len(xknots) == len(control)+1-degree, str("For clamped spline, knot vector with multiplicity must have length ",
|
||||
: type=="clamped" ? assert(len(xknots) == len(control)+1-degree, str("For clamped spline of degree ",degree,", knot vector with multiplicity must have length ",
|
||||
len(control)+1-degree," but has length ", len(xknots)))
|
||||
assert(xknots[0]!=xknots[1] && last(xknots)!=select(xknots,-2),
|
||||
"For clamped splint, first and last knots cannot repeat (must have multiplicity one")
|
||||
|
|
|
@ -1378,10 +1378,10 @@ module offset_stroke(path, width=1, rounded=true, start, end, check_valid=true,
|
|||
// atype = Select "hull", "intersect", "surf_hull" or "surf_intersect" anchor types. Default: "hull"
|
||||
// cp = Centerpoint for determining "intersect" anchors or centering the shape. Determintes the base of the anchor vector. Can be "centroid", "mean", "box" or a 3D point. Default: "centroid"
|
||||
// Anchor Types:
|
||||
// hull = Anchors to the convex hull of the linear sweep of the path, ignoring any end roundings. (default)
|
||||
// intersect = Anchors to the surface of the linear sweep of the path, ignoring any end roundings.
|
||||
// surf_hull = Anchors to the convex hull of the offset_sweep shape, including end treatments.
|
||||
// surf_intersect = Anchors to the surface of the offset_sweep shape, including any end treatments.
|
||||
// "hull" = Anchors to the convex hull of the linear sweep of the path, ignoring any end roundings. (default)
|
||||
// "intersect" = Anchors to the surface of the linear sweep of the path, ignoring any end roundings.
|
||||
// "surf_hull" = Anchors to the convex hull of the offset_sweep shape, including end treatments.
|
||||
// "surf_intersect" = Anchors to the surface of the offset_sweep shape, including any end treatments.
|
||||
// Named Anchors:
|
||||
// "base" = Anchor to the base of the shape in its native position, ignoring any "extra"
|
||||
// "top" = Anchor to the top of the shape in its native position, ignoring any "extra"
|
||||
|
@ -2120,13 +2120,11 @@ function _rp_compute_patches(top, bot, rtop, rsides, ktop, ksides, concave) =
|
|||
// "top_corner0", "top_corner1", etc = Top corner, pointing in direction of associated edge anchor, spin up along associated edge
|
||||
// "bot_corner0", "bot_corner1", etc = Bottom corner, pointing in direction of associated edge anchor, spin up along associated edge
|
||||
// Anchor Types:
|
||||
// hull = Anchors to the convex hull of the linear sweep of the path, ignoring any end roundings. (default)
|
||||
// intersect = Anchors to the surface of the linear sweep of the path, ignoring any end roundings.
|
||||
// surf_hull = Anchors to the convex hull of the offset_sweep shape, including end treatments.
|
||||
// surf_intersect = Anchors to the surface of the offset_sweep shape, including any end treatments.
|
||||
|
||||
// "hull" = Anchors to the virtual convex hull of the prism.
|
||||
// "intersect" = Anchors to the surface of the prism.
|
||||
// "hull" = Anchors to the VNF of the **unrounded** prism using VNF hull anchors (default)
|
||||
// "intersect" = Anchors to the VNF of the **unrounded** prism using VNF intersection anchors (default)
|
||||
// "surf_hull" = Use VNF hull anchors to the rounded VNF
|
||||
// "surf_intersect" = USe VFN intersection anchors to the rounded VNF
|
||||
// "prismoid" = For four sided prisms only, defined standard prismsoid anchors, with RIGHT set to the face closest to the RIGHT direction.
|
||||
// Example: Uniformly rounded pentagonal prism
|
||||
// rounded_prism(pentagon(3), height=3,
|
||||
// joint_top=0.5, joint_bot=0.5, joint_sides=0.5);
|
||||
|
@ -3384,7 +3382,7 @@ module join_prism(polygon, base, base_r, base_d, base_T=IDENT,
|
|||
overlap, base_overlap,aux_overlap,
|
||||
n=15, base_n, end_n, aux_n,
|
||||
fillet, base_fillet,aux_fillet,end_round,
|
||||
k=0.7, base_k,aux_k,end_k,
|
||||
k=0.7, base_k,aux_k,end_k,start,end,
|
||||
uniform=true, base_uniform, aux_uniform,
|
||||
debug=false, anchor="origin", extent=true, cp="centroid", atype="hull", orient=UP, spin=0,
|
||||
convexity=10)
|
||||
|
@ -3399,7 +3397,7 @@ module join_prism(polygon, base, base_r, base_d, base_T=IDENT,
|
|||
fillet=fillet, base_fillet=base_fillet, aux_fillet=aux_fillet, end_round=end_round,
|
||||
k=k, base_k=base_k, aux_k=aux_k, end_k=end_k,
|
||||
uniform=uniform, base_uniform=base_uniform, aux_uniform=aux_uniform,
|
||||
debug=debug,
|
||||
debug=debug, start=start, end=end,
|
||||
return_axis=true
|
||||
);
|
||||
axis = vnf_start_end[2] - vnf_start_end[1];
|
||||
|
@ -3424,7 +3422,7 @@ function join_prism(polygon, base, base_r, base_d, base_T=IDENT,
|
|||
fillet, base_fillet,aux_fillet,end_round,
|
||||
k=0.7, base_k,aux_k,end_k,
|
||||
uniform=true, base_uniform, aux_uniform,
|
||||
debug=false, return_axis=false) =
|
||||
debug=false, return_axis=false, start, end) =
|
||||
let(
|
||||
objects=["cyl","cylinder","plane","sphere"],
|
||||
length = one_defined([h,height,l,length], "h,height,l,length", dflt=undef)
|
||||
|
@ -3442,6 +3440,7 @@ function join_prism(polygon, base, base_r, base_d, base_T=IDENT,
|
|||
assert(is_num(scale) && scale>=0, "Prism scale must be non-negative")
|
||||
assert(num_defined([end_k,aux_k])<2, "Cannot define both end_k and aux_k")
|
||||
assert(num_defined([end_n,aux_n])<2, "Cannot define both end_n and aux_n")
|
||||
assert(prism_end_T==IDENT || num_defined([start,end])==0, "Cannot give prism_end_T with either start or end")
|
||||
let(
|
||||
base_r = get_radius(r=base_r,d=base_d),
|
||||
aux_r = get_radius(r=aux_r,d=aux_d),
|
||||
|
@ -3469,31 +3468,33 @@ function join_prism(polygon, base, base_r, base_d, base_T=IDENT,
|
|||
polygon=clockwise_polygon(polygon),
|
||||
start_center = CENTER,
|
||||
aux_T_horiz = submatrix(aux_T,[0:2],[0:2]) == ident(3) && aux_T[2][3]==0,
|
||||
dir = aux=="none" ? apply(aux_T,UP)
|
||||
dir = num_defined([start,end])==2 ? end-start
|
||||
: aux=="none" ? apply(aux_T,UP)
|
||||
: aux_T_horiz && in_list([base,aux], [["sphere","sphere"], ["cyl","cylinder"],["cylinder","cyl"], ["cyl","cyl"], ["cylinder", "cylinder"]]) ?
|
||||
unit(apply(aux_T, aux_r*UP))
|
||||
: apply(aux_T,CENTER)==CENTER ? apply(aux_T,UP)
|
||||
: apply(aux_T,CENTER),
|
||||
flip = short ? -1 : 1,
|
||||
axisline = [CENTER, flip*dir] + repeat(default(start,CENTER),2),
|
||||
start = base=="sphere" ?
|
||||
let( answer = _sphere_line_isect_best(abs(base_r),[CENTER,flip*dir], sign(base_r)*flip*dir))
|
||||
let( answer = _sphere_line_isect_best(abs(base_r),axisline, sign(base_r)*flip*dir))
|
||||
assert(answer,"Prism center doesn't intersect sphere (base)")
|
||||
answer
|
||||
: base=="cyl" || base=="cylinder" ?
|
||||
assert(dir.y!=0 || dir.z!=0, "Prism direction parallel to the cylinder")
|
||||
let(
|
||||
mapped = apply(yrot(90),[CENTER,flip*dir]),
|
||||
mapped = apply(yrot(90),axisline),
|
||||
answer = _cyl_line_intersection(abs(base_r),mapped,sign(base_r)*mapped[1])
|
||||
)
|
||||
assert(answer,"Prism center doesn't intersect cylinder (base)")
|
||||
apply(yrot(-90),answer)
|
||||
: is_path(base) ?
|
||||
let(
|
||||
mapped = apply(yrot(90),[CENTER,flip*dir]),
|
||||
mapped = apply(yrot(-90),axisline),
|
||||
answer = _prism_line_isect(pair(base,wrap=true),mapped,mapped[1])[0]
|
||||
)
|
||||
assert(answer,"Prism center doesn't intersect prism (base)")
|
||||
apply(yrot(-90),answer)
|
||||
apply(yrot(90),answer)
|
||||
: start_center,
|
||||
aux_T = aux=="none" ? move(start)*prism_end_T*move(-start)*move(length*dir)*move(start)
|
||||
: aux_T,
|
||||
|
@ -3501,7 +3502,8 @@ function join_prism(polygon, base, base_r, base_d, base_T=IDENT,
|
|||
aux = aux=="none" && aux_fillet!=0 ? "plane" : aux,
|
||||
end_center = apply(aux_T,CENTER),
|
||||
ndir = base_r<0 ? unit(start_center-start) : unit(end_center-start_center,UP),
|
||||
end_prelim = apply(move(start)*prism_end_T*move(-start),
|
||||
end_prelim = is_def(end) ? end
|
||||
:apply(move(start)*prism_end_T*move(-start),
|
||||
aux=="sphere" ?
|
||||
let( answer = _sphere_line_isect_best(abs(aux_r), [start,start+ndir], -sign(aux_r)*ndir))
|
||||
assert(answer,"Prism center doesn't intersect sphere (aux)")
|
||||
|
@ -3608,6 +3610,7 @@ function _sphere_line_isect_best(R, line, ref) =
|
|||
// point, ind ind and u are the segment index and u value. Prism is z-aligned.
|
||||
function _prism_line_isect(poly_pairs, line, ref) =
|
||||
let(
|
||||
|
||||
line2d = path2d(line),
|
||||
ref=point2d(ref),
|
||||
ilist = [for(j=idx(poly_pairs))
|
||||
|
@ -3621,7 +3624,7 @@ function _prism_line_isect(poly_pairs, line, ref) =
|
|||
isect2d = ilist[ind][0],
|
||||
isect_ind = ilist[ind][1],
|
||||
isect_u = ilist[ind][2],
|
||||
slope = (line[1].z-line[0].z)/norm(line[1]-line[0]),
|
||||
slope = (line[1].z-line[0].z)/norm(line2d[1]-line2d[0]),
|
||||
z = slope * norm(line2d[0]-isect2d) + line[0].z
|
||||
)
|
||||
[point3d(isect2d,z),isect_ind, isect_u];
|
||||
|
@ -3635,35 +3638,6 @@ function _prism_fillet(name, base, R, bot, top, d, k, N, overlap,uniform,debug)
|
|||
: is_path(base,2) ? _prism_fillet_prism(name, base, bot, top, d, k, N, overlap,uniform,debug)
|
||||
: assert(false,"Unknown base type");
|
||||
|
||||
function _prism_fillet_plane(name, bot, top, d, k, N, overlap,debug) =
|
||||
let(
|
||||
dir = sign(top[0].z-bot[0].z),
|
||||
isect = [for (i=idx(top)) plane_line_intersection([0,0,1,0], [top[i],bot[i]])],
|
||||
base_normal = -path3d(path_normals(path2d(isect), closed=true)),
|
||||
mesh = transpose([for(i=idx(top))
|
||||
let(
|
||||
|
||||
base_angle = vector_angle(top[i],isect[i],isect[i]+sign(d)*base_normal[i]),
|
||||
// joint length
|
||||
// d = r,
|
||||
r=abs(d)*tan(base_angle/2),
|
||||
// radius
|
||||
//d = r/tan(base_angle/2),
|
||||
// cut
|
||||
//r = r / (1/sin(base_angle/2) - 1),
|
||||
//d = r/tan(base_angle/2),
|
||||
prev = unit(top[i]-isect[i]),
|
||||
next = sign(d)*dir*base_normal[i],
|
||||
center = r/sin(base_angle/2) * unit(prev+next) + isect[i]
|
||||
)
|
||||
[
|
||||
each arc(N, cp=center, points = [isect[i]+prev*abs(d), isect[i]+next*d]),
|
||||
isect[i]+next*d+[0,0,-overlap*dir]
|
||||
]
|
||||
])
|
||||
)
|
||||
assert(debug || is_path_simple(path2d(select(mesh,-2)),closed=true),"Fillet doesn't fit: it intersects itself")
|
||||
mesh;
|
||||
|
||||
function _prism_fillet_plane(name, bot, top, d, k, N, overlap,debug) =
|
||||
let(
|
||||
|
|
|
@ -1355,9 +1355,9 @@ module frame_map(x,y,z,p,reverse=false)
|
|||
|
||||
// Function&Module: skew()
|
||||
//
|
||||
// Synopsis: Skews children along various axes.
|
||||
// Synopsis: Skews (or shears) children along various axes.
|
||||
// SynTags: Trans, Path, VNF, Mat
|
||||
// Topics: Affine, Matrices, Transforms, Skewing
|
||||
// Topics: Affine, Matrices, Transforms, Skewing, Shearing
|
||||
// See Also: move(), rot(), scale()
|
||||
//
|
||||
// Usage: As Module
|
||||
|
@ -1368,7 +1368,7 @@ module frame_map(x,y,z,p,reverse=false)
|
|||
// mat = skew([sxy=]|[axy=], [sxz=]|[axz=], [syx=]|[ayx=], [syz=]|[ayz=], [szx=]|[azx=], [szy=]|[azy=]);
|
||||
//
|
||||
// Description:
|
||||
// Skews geometry by the given skew factors.
|
||||
// Skews geometry by the given skew factors. Skewing is also referred to as shearing.
|
||||
// * Called as the built-in module, skews all children.
|
||||
// * Called as a function with a point in the `p` argument, returns the skewed point.
|
||||
// * Called as a function with a list of points in the `p` argument, returns the list of skewed points.
|
||||
|
@ -1572,4 +1572,48 @@ function _apply(transform,points) =
|
|||
"), data of dimension ",datadim));
|
||||
|
||||
|
||||
// Section: Saving and restoring
|
||||
|
||||
|
||||
$transform = IDENT;
|
||||
|
||||
module translate(v)
|
||||
{
|
||||
$transform = $transform * (is_vector(v) && (len(v)==2 || len(v)==3) ? affine3d_translate(point3d(v)) : IDENT);
|
||||
_translate(v) children();
|
||||
}
|
||||
|
||||
|
||||
module rotate(a,v)
|
||||
{
|
||||
rot3 = is_finite(a) && is_vector(v) && (len(v)==2 || len(v)==3) ? affine3d_rot_by_axis(v,a)
|
||||
: is_finite(a) ? affine3d_zrot(a)
|
||||
: same_shape(a,[0]) ? affine3d_xrot(a.x)
|
||||
: same_shape(a,[0,0]) ? affine3d_yrot(a.y)*affine3d_xrot(a.x)
|
||||
: same_shape(a,[0,0,0])? affine3d_zrot(a.z)*affine3d_yrot(a.y)*affine3d_xrot(a.x)
|
||||
: IDENT;
|
||||
$transform = $transform * rot3;
|
||||
_rotate(a=a,v=v) children();
|
||||
}
|
||||
|
||||
module scale(v)
|
||||
{
|
||||
s3 = is_finite(v) ? affine3d_scale([v,v,v])
|
||||
: is_vector(v) ? affine3d_scale(v)
|
||||
: IDENT;
|
||||
$transform = $transform * s3;
|
||||
_scale(v) children();
|
||||
}
|
||||
|
||||
|
||||
module multmatrix(m)
|
||||
{
|
||||
m3 = !is_matrix(m) ? IDENT
|
||||
: len(m)>0 && len(m)<=4 && len(m[0])>0 && len(m[0])<=4 ? submatrix_set(IDENT, m)
|
||||
: IDENT;
|
||||
$transform = $transform * m3;
|
||||
_multmatrix(m) children();
|
||||
}
|
||||
|
||||
|
||||
// vim: expandtab tabstop=4 shiftwidth=4 softtabstop=4 nowrap
|
||||
|
|
20
vectors.scad
20
vectors.scad
|
@ -343,6 +343,26 @@ function vector_bisect(v1,v2) =
|
|||
) v3;
|
||||
|
||||
|
||||
// Function: vector_perp()
|
||||
// Synopsis: Returns component of a vector perpendicular to a second vector
|
||||
// Topics: Vectors, Math
|
||||
// Usage:
|
||||
// perp = vector_perp(v,w);
|
||||
// Description:
|
||||
// Returns the component of vector w that is perpendicular to vector v. Vectors must have the same length.
|
||||
// Arguments:
|
||||
// v = reference vector
|
||||
// w = vector whose perpendicular component is returned
|
||||
// Example(2D): We extract the component of the red vector that is perpendicular to the yellow vector. That component appears in blue.
|
||||
// v = [12,6];
|
||||
// w = [13,22];
|
||||
// stroke([[0,0],v],endcap2="arrow2");
|
||||
// stroke([[0,0],w],endcap2="arrow2",color="red");
|
||||
// stroke([[0,0],vector_perp(v,w)], endcap2="arrow2", color="blue");
|
||||
function vector_perp(v,w) =
|
||||
assert(is_vector(v) && is_vector(w) && len(v)==len(w), "Invalid or mismatched inputs")
|
||||
w - w*v*v/(v*v);
|
||||
|
||||
|
||||
// Section: Vector Searching
|
||||
|
||||
|
|
Loading…
Reference in a new issue