PDA

View Full Version : Can LW create an edge on either side of an edge at ___ distance?



TrueSongMedia
12-11-2014, 07:49 AM
In Modo 801, I can bevel an edge and leave it sharp - creating an edge on either side at an exact distance (i.e. 20mm). This is an easy way to make edge loops for subpatching.

126008

Can Lightwave do this? If so, what is the tool called?

I don't want to use Rounder due to it's dislike of some geometry, and I don't know that Rounder can give me a sharp edge like this, can it? Edge Bevel just flattens the edge out...

I'm using LW 11.6.3 if that makes a difference. Any ideas?

Kryslin
12-11-2014, 10:57 AM
Bevel (Multiply -> Extend -> Bevel) will do that with a single polygon; Multishift will do it for entire selections (Multiply -> Extend -> Multishift, be sure to have 'Group Polygons" checked. Alternatives include Edit Edges (Detail -> Edit Edges) and LWCAD's line tool (with ruler snap enabled)(Not a native tool, but very useful).

When using Bevel / Multishift, use the numeric panel to enter your inset distance.

TrueSongMedia
12-11-2014, 05:46 PM
Thanks for the reply, Kryslin. :)

The problem with multishift (though it's a tool I use a lot) is that it creates unnecessary geometry, where I just need two edges to sharpen an edge for subpatching. Edit edges might work. I'll have to test it out.

I'd like to get LWCAD, but right now my options on the table are LWCAD and 2015 or Modo upgrade. Honestly, at the moment anyway, I like Modo's modeling toolset and performance better. I do like Lightwave for rendering though. Each has capabilities the other doesn't I suppose.

faulknermano
12-12-2014, 03:01 AM
I wrote this suite of scripts to move shift edges to specific distances from neighbouring edges.

The first script is to *globally* set the desired width. If you select two points, then the script will detect the distance between those two points and set that as the distance (which is convenient when you already have an edge you like). If you don't select anything, the script will prompt you for your desired distance.

This is the first script (MoveToEdgeSetWidth.ls):



//written by Lernie Ang, faulknermano
@warnings 0
main
{
globalWidth = number(globalrecall("MoveToEdge_Width",0));
selmode(DIRECT);
pc = editbegin();
if(pc == 0)
{
reqbegin("Set global MoveToEdge width manually");
c1 = ctldistance("Distance",globalWidth);
return if(!reqpost());
dist = getvalue(c1);
reqend();
}
else if(pc == 1)
{
warn("Setting global MoveToEdge width to zero.");
dist = 0;
}
else
{
dist = vmag(pointinfo(points[2]) - pointinfo(points[1]));
}
globalstore("MoveToEdge_Width",dist);
info("Set width distance to ",dist);

}



The next three scripts are the ones that actually move the selected edge; as the user, you have to have an existing edge to move, and it must be selected -- it doesn't have to be a full edge loop, though.

This script is MoveToEdge.ls, and if you run this it will try to detect the closer of the two edges it is flanked with, and moves towards that direction. This is meant as a convenience feature, but most of the time, I usually create a Bandsaw edge right down the middle, and this script will 50% of the time guess the wrong edge to move towards. So I use the other two scripts, which I will inline further below.

This is the MoveToEdge.ls:



//written by Lernie Ang, faulknermano
@warnings 0
main
{
globalSide = integer(globalrecall("MoveToEdge_Side",0));
globalWidth = number(globalrecall("MoveToEdge_Width",0));

// take an edge and find the two edges surrounding it.
// take the nearest edge and then select it.

selmode(USER);
pc = editbegin();
if(!pc)
error("No selection.");

//~ take the whole selection of points; each point's role is to get two directions going to its appropriate edge depending
//~ if there is a pairing-point.
//~ so, for each vert: determine polys it belongs to
//~ then store the directions where there is no pairing-point
freePointNdx = 0;

freePointArray = nil;
for(i=1;i<=pc;i++)
{
pnts[i] = points[i];
}
// take the second point and then the first

// tale the first point and then scan the vicinity for the second point
// find common poly
nextVertPair = findVertEdgePair(points[1], nil, pnts);
p1 = nextVertPair;
p2 = pnts[1];

firstCommonPolys = findCommonPolys(p1,p2);

nextVertPair = findVertEdgePair(p1, p2, pnts);
if(nextVertPair) // this is the next edge point in the vicinity
finVertPair = nextVertPair;
nextVertPair = findVertEdgePair(p1, p2, pnts);
if(nextVertPair) // this is the next edge point in the vicinity
finVertPair = nextVertPair;
f[f.size()+1] = finVertPair;

freePoint[freePoint.size()+1,1] = p2;
(ep,mySide) = findFreePoint(p2,p1, firstCommonPolys[1]);
mySide = !mySide;
freePoint[freePoint.size(),mySide+2] = ep;
(ep,mySide) = findFreePoint(p2,p1, firstCommonPolys[2]);
mySide = !mySide;
freePoint[freePoint.size(),mySide+2] = ep;

freePoint[freePoint.size()+1,1] = p1;
(ep,mySide) = findFreePoint(p1,p2, firstCommonPolys[1]);
freePoint[freePoint.size(),mySide+2] = ep;
(ep,mySide) = findFreePoint(p1,p2, firstCommonPolys[2]);
freePoint[freePoint.size(),mySide+2] = ep;

processedPoints[processedPoints.size()+1] = p1;


// look at second vert, detect common poly, find cPnt vert that is not yet been processed
for(i=2;i<pnts.size();i++)
{
p2 = p1;
p1 = finVertPair; // this makes the second vert the first one in the list now

nextCommonPolys = findCommonPolys(p1,p2);


if(size(nextCommonPolys) > 1)
{
finVertPair = nil;
nextVertPair = findVertEdgePair(p1, p2, pnts);
if(nextVertPair) // this is the next edge point in the vicinity
finVertPair = nextVertPair;
else
nextVertPair = findVertEdgePair(p1, p2, pnts);
if(nextVertPair) // this is the next edge point in the vicinity
finVertPair = nextVertPair;



f[f.size()+1] = finVertPair;

freePoint[freePoint.size()+1,1] = p1;

(ep,mySide) = findFreePoint(p1, p2, nextCommonPolys[1]);

freePoint[freePoint.size(),mySide+2] = ep;
(ep,mySide) = findFreePoint(p1,p2, nextCommonPolys[2]);

freePoint[freePoint.size(),mySide+2] = ep;

processedPoints[processedPoints.size()+1] = p1;
if(finVertPair == nil)
continue;

}


}

for(i=1;i<=freePoint.size();i++)
{
mag1 = vmag(pointinfo(freePoint[i,2]) - pointinfo(freePoint[i,1]));
mag2 = vmag(pointinfo(freePoint[i,3]) - pointinfo(freePoint[i,1]));
if(globalSide != 0)
{
mySide = globalSide;
}
else if(mag1 < mag2)
{
mySide = 2;
}
else
mySide = 3;

vec = pointinfo(freePoint[i,mySide]) - pointinfo(freePoint[i,1]);
if(globalWidth == 0)
edgewidth = .1;
else
edgewidth = globalWidth;
//~ edgewidth = .1;

myMag = vmag(vec);
offset = myMag - edgewidth;
offsetScale = offset / myMag;
//~ info(edgewidth);
finMove = vec * offsetScale;
moveArray[i] = finMove;

}

for(i=1;i<=moveArray.size();i++)
{
pointmove(freePoint[i,1],pointinfo(freePoint[i,1]) + moveArray[i]);
}

editend();
globalstore("MoveToEdge_Side",0);
}

containsOneOfThese: str, array
{
for(i=1;i<=array.size();i++)
{
if(array[i] == str)
return(true);
}
return(false);
}

findFreePoint: curVert, vertPair, poly1
{
// finds the other edge vert (single) of poly1
// this looks at the direct neighbour of cPnts only, but this only selects a single point that is in direct line of
// connection the curVert (current vert being processed)

//~ find the index of curVert

for(i=1;i<=poly1.pointCount;i++)
{
if(curVert == poly1.points[i])
{
ndx = i;
break;
}
}

// search +1 and -1
if(ndx == 1)
{
highPointNdx = ndx + 1;
lowPointNdx = poly1.pointCount;
}
else if(ndx == poly1.pointCount)
{
highPointNdx = 1;
lowPointNdx = ndx - 1;
}
else
{
highPointNdx = ndx + 1;
lowPointNdx = ndx - 1;
}
highPoint = poly1.points[highPointNdx];
lowPoint = poly1.points[lowPointNdx];

// if the searched point is not a cPnt
if(highPoint != vertPair)
{

edgePnt = highPoint;
side = 0;
//~ info(edgePnt," ",side);
}
else
{
edgePnt = lowPoint;
side = 1;
//~ info(edgePnt," ",side);
}


return(edgePnt,side);

}

isCommonPoly: poly1, cPnts
{
found = 0;
for(i=1;i<=poly1.pointCount;i++)
{
for(j=1;j<=cPnts.size();j++)
{
if(cPnts[j] == poly1.points[i])
{
found++;
break;

}
}

}
if(found > 1)
return(true);
else
return(false);
}

findVertEdgePair: curVert, exceptVert, cPnts
{
cpoly = curVert.polygon();
for(i=1;i<=cpoly.size();i++)
{
for(j=1;j<=cpoly[i].pointCount;j++)
{

if(cpoly[i].points[j] != exceptVert && cpoly[i].points[j] != curVert && cPnts.contains(cpoly[i].points[j])) // means that this is a vertedgepair
{
//~ info(exceptVert);
//~ info("ret",cpoly[i].points[j]);
return(cpoly[i].points[j]);
}
}

}
return(nil);
}

findCommonPolys: p1, p2
{
k = 0;
a = p1.polygon();

if(p2 == nil)
return(a);

b = p2.polygon();

for(i=1;i<=a.size();i++)
{
for(j=1;j<=b.size();j++)
{
if(a[i] == b[j])
cp[++k] = a[i];
}

}
if(cp)
return(cp);
else
return(nil);
}



The last two scripts is MoveToEdgeLeft.ls and MoveToEdgeRight.ls. I assign these scripts to hotkeys.

MoveToEdgeLeft.ls:



main
{
globalstore("MoveToEdge_Side",3);
cmdseq("MoveToEdge");
}


MoveToEdgeRight.ls:



main
{
globalstore("MoveToEdge_Side",2);
cmdseq("MoveToEdge");
}



To recap:

MoveToEdge.ls - main script that moves the edge. This script is must be installed as a plugin because it is called by the other two scripts MoveToEdgeLeft.ls and MoveToEdgeRight.ls. When executed on its own, it will try to find the nearest edge to move towards.
MoveToEdgeLeft.ls and MoveToEdgeRight.ls - two scripts that move towards the right or left side of a given edge loop. The side depends on what direction you selected your loop (based on order of edge/point selection)
MoveToEdgeSetWidth.ls - sets the distance and stores it globally; this means that the distance will remain across sessions.

I have all four scripts mapped as hotkeys because I use them very frequently.