Given a mesh model (e.g. a box) and a robot template containing volume, aspect ratio and linkage info of sub-parts (basically cuboids), we want to have a cutting algorithm to cut the mesh model into pieces that can match the robot template. We are using Maya for the modelling job.
For example, the mesh model is a 1X1X1 volume=1 box, the robot template has a 1:1:2 volume 0.5 head link with body, and a 1:1:2 volume 0.5 body link with head, then what we need is to cut the box into half.
The matching of volume, aspect ratio and linkage are not strict, reasonable errors can be accepted.
Is there any existing algorithms that can do the job or is there any related topics on this?
Also if you have any idea to solve this problem please enlighten me. Thanks!
EDIT
The problem is, given a mesh object, and a robot template, we need to transform it to the robot.
So now my idea is first cut the object into subparts which match the template, then transform the subparts into robot using Inverse Kinematic maybe.
Sample input and output:
I'd try to just cubes to the correct dimensions by setting the aspect ratio in the cube shape
import maya.cmds as cmds
def scaled_cube(volume, w, d, h):
scale_factor = pow( float(volume) / float(h* w * d), 1.0/3)
return cmds.polyCube(w = w * scale_factor, d = d * scale_factor, h = h * scale_factor)
Edit: After the above comments, this will cut out the portion of a mesh contained in a cuboid (defined here as a maya style bounding box (minx, miny, minz, maxx, maxy, maxz - the same thing you'd get from querying the maya bbox):
def cut_to_fit_bounds(mesh, bbox):
'''
splits an existing mesh
'''
cutmesh = cmds.duplicate(mesh)
minx, miny, minz, maxx, maxy, maxz = bbox
cmds.select(cutmesh)
cmds.polyCut(pc = (minx, 0, 0), ro = (0, 90,0), df =1, ch=0 )
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (maxx, 0, 0), ro = (0, -90,0), df = 1, ch=0)
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (0, 0, minz), ro = (0, 0,0), df =1, ch=0 )
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (0, 0, maxz), ro = (0, 180,0), df = 1, ch=0)
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (0, miny, 0), ro = (-90, 0,0), df =1,ch=0 )
cmds.polyCloseBorder(ch=0)
cmds.polyCut(pc = (0, maxy, 0), ro = (90, 0,0), df = 1, ch=0)
cmds.polyCloseBorder(ch=0)
cmds.select(cutmesh)
The previous routine could be used to create appropriately sized volumes - by placing them correctly and grabbing their bounding boxes with cmds.xform(q=True, bb=True) cut volumes could be made. After that you should have a cut up copy of the original, although I'd worry about normal artifacts, sliver polys and material issues which are common when using polyCut.
Related
For a sample size n=1000, I plot the following graph based the code
n = 1000;
m = RandomVariate[GaussianOrthogonalMatrixDistribution[Sqrt[2]/Sqrt[n], n]];
{eval, evec} = Eigensystem[m];
h = evec[[All, 1]];
imin = Ordering[eval, 1][[1]];
lambda2minlambda1 = Sort[eval][[2]] - Sort[eval][[1]];
tn = 1/(4*lambda2minlambda1);
Plot the function H1 (t)
Plot[Abs[h[[imin]]]*Exp[-2*eval[[imin]]*t]/Sqrt[Sum[h[[i]]^2*Exp[-4*eval[[i]]*t], {i, 1, n}]],
{t, 0, 10*tn},
GridLines -> {{tn}, {1}},
GridLinesStyle -> Directive[{Red, Blue}, Thickness[0.008]],
PlotRange -> Full]
Question:
How can I put all graphs for different sample size n=10, 100, 1000, 2000 in the same plot and change the color of y=1 in red?**
Try
Show[Append[Table[
m=RandomVariate[GaussianOrthogonalMatrixDistribution[Sqrt[2]/Sqrt[n], n]];
{eval,evec}=Eigensystem[m];h=evec[[All,1]];imin=Ordering[eval,1][[1]];
lambda2minlambda1=Sort[eval][[2]]-Sort[eval][[1]];tn=1/(4*lambda2minlambda1);
Plot[Abs[h[[imin]]]*Exp[-2*eval[[imin]]*t]/Sqrt[Sum[h[[i]]^2*Exp[-4*eval[[i]]*t],
{i,1,n}]],{t,0,10*tn},PlotRange->{{0,60},{0,1}}],
{n,{10,100,1000,2000}}],
Plot[1,{x,0,60},ColorFunction->Function[{x,y},Red]]],
PlotRange->{{0,60},{0,1}}]
There are always at least a dozen different ways of doing anything in Mathematica. Pick one that you can remember and use without making any mistakes.
Hello, I've got a question which I cannot solve so I need a bit help.
In the picture above you can see an Oriented Bounding Box specified by 4 points (A, B, C, D). There is also a point in space called P. If I cast a ray from P against the OBB the ray is going to intersect the OBB at some point. This point of intersection is called Q in the picture. By the way the ray is always going to be x-axis aligned which means its directional vector is either (1, 0) or (-1,0) if normalized. My goal is to find the point of intersection - Q. Is there a way (if possible computationaly inexpensive) to do so?
Thanks in advance.
One way to do this is to consider each side of the bounding box to be a linear equation of the form y = ax + b, where a is the slope and b is the y-intercept. Then consider the ray from P to be an equation of the form y = c, where c is a constant. Then compare this equation to each of the four other equations to see where it intersects each one. One of these intersections will be our Q, if a Q exists; it's possible that the ray will miss the bounding box entirely. We will need to do a few checks:
Firstly, eliminate all potential Q's that are on the wrong side of P.
Secondly, check each of the four intersections to make sure they are within the bounds of the lines that they represent, and eliminate the ones that are not.
Finally, if any potential Q's remain, the one closest to P will be our Q. If no potential Q's remain, this means that the ray from P misses the bounding box entirely.
For example...
The line drawn from D to B would have a slope equal to (B.y - D.y) / (B.x - D.x) and a y-intercept equal to B.y - B.x * slope. Then the entire equation is y = (B.y - D.y) / (B.x - D.x) * x + B.y - B.x * (B.y - D.y) / (B.x - D.x). Set this equation equal to y = P.y and solve for x:
x = (P.y - B.y + B.x*(B.y - D.y)/(B.x - D.x))*(B.x - D.x)/(B.y - D.y)
The result of this equation will give you the x-value of the intersection. The y-value is P.y. Do this for each of the other 3 lines as well: A-B, A-C, C-D. I will refer to these intersections as Q(D-B), Q(A-B), Q(A-C), and Q(C-D) respectively.
Next, eliminate candidate-Q's that are on the wrong side of P. In our example, this eliminates Q(A-B), since it is way off to the right side of the screen. Mathematically, Q(A-B).x > P.x.
Then eliminate all candidate-Q's that are not on the line they represent. We can do this check by finding the lowest and highest x-values and y-values given by the two points that represent the line. For example, to check that Q(A-C) is on the line A-C, check that C.x <= Q(A-C).x <= A.x and C.y <= Q(A-C).y <= A.y. Q(A-C) passes the test, as well as Q(D-B). However, Q(C-D) does not pass, as it is way off to the left side of the screen, far from the box. Therefore, Q(C-D) is eliminated from candidacy.
Finally, of the two points that remain, Q(A-C) and Q(D-B), we choose Q(D-B) to be our winner, because it is closest to P.
We now can say that the ray from P hits the bounding box at Q(D-B).
Of course, when you implement this in code, you will need to account for divisions by zero. If a line is perfectly vertical, there does not exist a point-slope equation of the line, so you will need to create a separate formula for this case. If a line is perfectly horizontal, it's respective candidate-Q should be automatically eliminated from candidacy, as the ray from P will never touch it.
Edit:
It would be more efficient to only do this process with lines whose two points are on vertically opposite sides of point P. If both points of a line are above P, or they are both below P, they would be eliminated from candidacy from the beginning.
Find the two sides that straddle p on Y. (Test of the form (Ya < Yp) != (Yb < Yp)).
Then compute the intersection points of the horizontal by p with these two sides, and keep the first to the left of p.
If the ray points to the left(right) then it must intersect an edge that connects to the point in the OOB with max(min) x-value. We can determine which edge by simply comparing the y-value of the ray with the y value of the max(min) point and its neighbors. We also need to consider OBBs that are actually axis-aligned, and thus have two points with equal max(min) x-value. Once we have the edge it's simple to confirm that the ray does in fact intersect the OBB and calculate its x-value.
Here's some Java code to illustrate (ideone):
static double nearestX(Point[] obb, int y, int dir)
{
// Find min(max) point
int n = 0;
for(int i=1; i<4; i++)
if((obb[n].x < obb[i].x) == (dir == -1)) n = i;
// Determine next or prev edge
int next = (n+1) % 4;
int prev = (n+3) % 4;
int nn;
if((obb[n].x == obb[next].x) || (obb[n].y < y) == (obb[n].y < obb[next].y))
nn = next;
else
nn = prev;
// Check that the ray intersects the OBB
if(Math.abs(y) > Math.abs(obb[nn].y)) return Double.NaN;
// Standard calculation of x from y for line segment
return obb[n].x + (y-obb[n].y)*(obb[nn].x-obb[n].x)/(obb[nn].y-obb[n].y);
}
Test:
public static void main(String[] args)
{
test("Diamond", new Point[]{p(0, -2), p(2, 0), p(0, 2), p(-2,0)});
test("Square", new Point[]{p(-2, -2), p(2, -2), p(2, 2), p(-2,2)});
}
static void test(String label, Point[] obb)
{
System.out.println(label + ": " + Arrays.toString(obb));
for(int dir : new int[] {-1, 1})
{
for(int y : new int[] {-3, -2, -1, 0, 1, 2, 3})
System.out.printf("(% d, % d) = %.0f\n", y , dir, nearestX(obb, y, dir));
System.out.println();
}
}
Output:
Diamond: [(0,-2), (2,0), (0,2), (-2,0)]
(-3, -1) = NaN
(-2, -1) = 0
(-1, -1) = 1
( 0, -1) = 2
( 1, -1) = 1
( 2, -1) = 0
( 3, -1) = NaN
(-3, 1) = NaN
(-2, 1) = 0
(-1, 1) = -1
( 0, 1) = -2
( 1, 1) = -1
( 2, 1) = 0
( 3, 1) = NaN
Square: [(-2,-2), (2,-2), (2,2), (-2,2)]
(-3, -1) = NaN
(-2, -1) = 2
(-1, -1) = 2
( 0, -1) = 2
( 1, -1) = 2
( 2, -1) = 2
( 3, -1) = NaN
(-3, 1) = NaN
(-2, 1) = -2
(-1, 1) = -2
( 0, 1) = -2
( 1, 1) = -2
( 2, 1) = -2
( 3, 1) = NaN
Seems like it's not as simple as RGB1*A1 + RGB2*A2...how are values clipped? Weighted? Etc.
And is this a context-dependent question? Are there different algorithms, that produce different results? Or one standard implementation?
I'm particularly interested in OpenGL-specific answers, but context from other environments is useful too.
I don't know about OpenGL, but one pixel of opacity A is usually drawn on another pixel like so:
result.r = background.r * (1 - A) + foreground.r * A
result.g = background.g * (1 - A) + foreground.g * A
result.b = background.b * (1 - A) + foreground.b * A
Repeat this operation for multiple pixels.
The above answer works if the image isn't premultiplied alpha. However if you use that type of blending with a premultiplied alpha image, there will be a black border.
Premultiplied Alpha:
When the image is created, the color values are multiplied by the alpha channel. Take a look at this one pixel example:
Pixel: r = 1, g = 0, b = 0, a = 0.5
When it's saved, the rgb vales will be multiplied by the alpha value giving:
Pixel: r = 0.5, g = 0, b = 0, a = 0.5
To blend this kind of image you need to use the following formula:
result.r = background.r * (1 - A) + foreground.r
result.g = background.g * (1 - A) + foreground.g
result.b = background.b * (1 - A) + foreground.b
Non-premultiplied Alpha
In this example, the alpha channel is completely separate to the color channels.
Pixel: r = 1, g = 0, b = 0, a = 0.5
When it's saved:
Pixel: r = 1, g = 0, b = 0, a = 0.5
It's the same. In this case the answer provided by minitech is correct.
More details can be found here: Premultiplied alpha
Seems like it's not as simple as RGB1*A1 + RGB2*A2...how are values clipped? Weighted? Etc.
And is this a context-dependent question? Are there different algorithms, that produce different results? Or one standard implementation?
I'm particularly interested in OpenGL-specific answers, but context from other environments is useful too.
I don't know about OpenGL, but one pixel of opacity A is usually drawn on another pixel like so:
result.r = background.r * (1 - A) + foreground.r * A
result.g = background.g * (1 - A) + foreground.g * A
result.b = background.b * (1 - A) + foreground.b * A
Repeat this operation for multiple pixels.
The above answer works if the image isn't premultiplied alpha. However if you use that type of blending with a premultiplied alpha image, there will be a black border.
Premultiplied Alpha:
When the image is created, the color values are multiplied by the alpha channel. Take a look at this one pixel example:
Pixel: r = 1, g = 0, b = 0, a = 0.5
When it's saved, the rgb vales will be multiplied by the alpha value giving:
Pixel: r = 0.5, g = 0, b = 0, a = 0.5
To blend this kind of image you need to use the following formula:
result.r = background.r * (1 - A) + foreground.r
result.g = background.g * (1 - A) + foreground.g
result.b = background.b * (1 - A) + foreground.b
Non-premultiplied Alpha
In this example, the alpha channel is completely separate to the color channels.
Pixel: r = 1, g = 0, b = 0, a = 0.5
When it's saved:
Pixel: r = 1, g = 0, b = 0, a = 0.5
It's the same. In this case the answer provided by minitech is correct.
More details can be found here: Premultiplied alpha
I'm using OpenCV to fit a line from a set of points using cvFitLine()
cvFitLine() returns a normalized vector that is co-linear to the line and a point on the line.
See details here
Using this information how can I get the equation of a line so that I can draw the line?
If cvFitLine() returns normalized vector (vx,vy) and point (x0,y0), then the equation of the line is
(x,y) = (x0,y0) + t*(vx,vy)
where t runs from −∞ to +∞.
This is what you asked for, but probably isn't immediately helpful in drawing the line. You would want to clip it either to the screen boundaries, or perhaps the bounding box of the the original set of points. To clip a line to a rectangle, just solve for values of t where the line crosses the boundary of the rectangle.
Just draw a big line instead of solving for the boundaries. eg:
cv.Line(img, (x0-m*vx[0], y0-m*vy[0]), (x0+m*vx[0], y0+m*vy[0]), (0,0,0))
will do it for example.. for m large enough :)
This just spells out #brainjam's answer in python for any passers by.
The formula for a line using a unit vector (vx, vy) and some point on the line (x0, y0) is:
(x, y) = (x0, y0) + t*(vx, vy)
The return from cv2.fitLine() is:
np.array([vx, vy, x0, y0])
In the example case, I have a line spanning the height of my image, so I want to find the t0 and t1 that intersect with y=0 and y=img.shape[0] (the top/bottom boundaries).
# get the fitLine for your set of points in the array, `line`
fit_line = cv2.fitLine(line, cv2.DIST_L2, 0, 0.01, 0.01)
# compute t0 for y=0 and t1 for y=img.shape[0]: (y-y0)/vy
t0 = (0-fit_line[3])/fit_line[1]
t1 = (img.shape[0]-fit_line[3])/fit_line[1]
# plug into the line formula to find the two endpoints, p0 and p1
# to plot, we need pixel locations so convert to int
p0 = (fit_line[2:4] + (t0 * fit_line[0:2])).astype(np.uint32)
p1 = (fit_line[2:4] + (t1 * fit_line[0:2])).astype(np.uint32)
# draw the line. For my version of opencv, it wants tuples so we
# flatten the arrays and convert
# args: cv2.line(image, p0, p1, color, thickness)
cv2.line(img, tuple(p0.ravel()), tuple(p1.ravel()), (0, 255, 0), 10)
I used a strategy similar to Karpathy up there but used an extra function. As you can see, I'm using cvClipLine to trim the line to the size of the image, which is unnecessary but does add a little niceness.
Also the multiplier here is defined as theMult = max(img->height,img->width) so we dont get numbers that might one day overflow or something.
void drawLine(IplImage * img, float line[4], int thickness,CvScalar color)
{
double theMult = max(img->height,img->width);
// calculate start point
CvPoint startPoint;
startPoint.x = line[2]- theMult*line[0];// x0
startPoint.y = line[3] - theMult*line[1];// y0
// calculate end point
CvPoint endPoint;
endPoint.x = line[2]+ theMult*line[0];//x[1]
endPoint.y = line[3] + theMult*line[1];//y[1]
// draw overlay of bottom lines on image
cvClipLine(cvGetSize(img), &startPoint, &endPoint);
cvLine(img, startPoint, endPoint, color, thickness, 8, 0);
}
Adding to #brainjam answer:
To clip to the bounding box of original set of points:
// std::vector<Point2i> points = ...
//lineParams: [vx,vy, x0,y0]: (normalized vector, point on our contour)
Vec4f lineParams; fitLine(points, lineParams, CV_DIST_L2, 0, 0.01, 0.01);
// derive the bounding xs of points
decltype(points)::iterator minXP, maxXP;
std::tie(minXP, maxXP) = std::minmax_element(points.begin(), points.end(), [](const Point2i& p1, const Point2i& p2){ return p1.x < p2.x; });
// derive y coords of fitted line
float m = lineParams[1] / lineParams[0];
int y1 = ((minXP->x - lineParams[2]) * m) + lineParams[3];
int y2 = ((maxXP->x - lineParams[2]) * m) + lineParams[3];
line(clearTarget, Point(minXP->x, y1), Point(maxXP->x, y2), Scalar(255, 255, 255), 2);
To clip to the entire image boundaries substitute minXP->x to 0 and maxXP->x to image.cols - 1, which was originally answered in https://stackoverflow.com/a/14192660/2380455
we use a " Vec4f fitedLine;" for fitted Line
in fitLine we have 4 parameters
if we consider Line relation az bellow:
Y - Y0 = M (X - X0)
we have
Y0 = FitedLine[3];
X0 = FitedLine[2];
m = FitedLine[1]/FitedLine[0];
so we have a Line equation we can find other points on it.