Welcome to the Onshape forum! Ask questions and join in the discussions about everything Onshape.
First time visiting? Here are some places to start:- Looking for a certain topic? Check out the categories filter or use Search (upper right).
- Need support? Ask a question to our Community Support category.
- Please submit support tickets for bugs but you can request improvements in the Product Feedback category.
- Be respectful, on topic and if you see a problem, Flag it.
If you would like to contact our Community Manager personally, feel free to send a private message or an email.
how to query for all vertexes in a mesh
tommie_berry
Member Posts: 12 ✭✭
how to query for all vertexes in a mesh
0
Best Answers
-
kevin_o_toole_1 Onshape Employees, Developers, HDM Posts: 565Unfortunately I don't think there is a method of doing that in FeatureScript. If you'd like, you can submit an improvement request for this functionality.5
-
lana Onshape Employees Posts: 706@tommie_berry
If you can get point coordinates as csv file this feature can be used to build a spline5 -
philip_thomas Member, Moderator, Onshape Employees, Developers Posts: 1,381There is an updated XYZ custom feature that takes advantage of 'Reference Parameters' (the ability to point a custom feature to different data sources)
https://cad.onshape.com/documents/a5566bc4a7c123d4958fd925/w/de9e3b016a0232b5b8ec183d/e/97994fc552ad661c4611715d
Philip Thomas - Onshape5 -
tommie_berry Member Posts: 12 ✭✭Yes, it is easy to extract all vertex points from the .stl file. Sorting them into each plane of the original scan is very difficult. The original scan planes are all parallel. I used the 3D points program in featurescript to create 3D splines, but you can only loft between 2D splines. So you have to create 2D closed splines from all the points close (<0.1mm) to one scan plane.
then go to the next plane. So I agree, I can use the extracted points from a csv. But it would have been so much easier to query for all the points.0 -
billy2 Member, OS Professional, Mentor, Developers, User Group Leader Posts: 2,068 PRO@tommie_berry
Sorry for the late post, haven't had the time to dig up an old project I've worked on. I was working on point clouds and selecting planar points from cloud. I also had points close to faces. I also have an opinion about all this.
Cloud of points read from obj file:
points close to a plane:
You iterate through cloud and evaluate distance from plane to point. I think these are 1mm close to this plane. If you wanted all points on the plane, then you would have 0 points, mathematically no points are on the plane. You could project points onto the plane and then try and create a spline. Please keep in mind that these are an unsorted list and to create a spline you're going sort points from top to bottom. Then you'll end up with a crappy looking curve.
Then I asked for points closest to some faces:
I don't know what you'd do with these?
I have the code and would be happy to share it with you if you want it. The command you're looking for is eval distance.
My opinion:
I don't think it's practical to expect some algorithm to look at all the chaos in a cloud of points and come up with some geometry that'll be worth any thing. I'm no mathematician, and possibly you are, but I found this to be a dead end road.
What's working for me, is to bring in a mesh and use it as a visual guide:
It's so easy for a human to fit a spline through some chaotic point cloud and get a great shape.
Once again this my opinion, but I think an art student from your local community collage can out perform a $1,000,000 computer algorithm trying to do the same thing.
6 -
tommie_berry Member Posts: 12 ✭✭Thank you, that was very helpful.
if you could send that code to tom@berry.org I am very interested.0 -
billy2 Member, OS Professional, Mentor, Developers, User Group Leader Posts: 2,068 PRO
FeatureScript 370; import(path : "onshape/std/geometry.fs", version : "370.0"); import(path : "c7c1d6986e28b170c61450e7", version : "e5c1f8fac7228a89a9e1153b"); function parseVertex(s is string) // Returns a unitless 3D Vector or undefined { const regexp = "v\\s+" ~ REGEX_NUMBER_CAPTURE ~ "\\s+" ~ REGEX_NUMBER_CAPTURE ~ "\\s+" ~ REGEX_NUMBER_CAPTURE ~ "\\s*"; const matches = match(s, regexp); if (!matches.hasMatch) return undefined; var result = makeArray(3); for (var i in [0, 1, 2]) result[i] = stringToNumber(matches.captures[i + 1]); return vector(result); } export const MY_COUNT_BOUNDS = { "min" : 0, "max" : 1e9, (unitless) : [0, 50, 1e5] } as IntegerBoundSpec; annotation { "Feature Type Name" : "objData", "UIHint" : "NO_PREVIEW_PROVIDED" } export const objData = defineFeature(function(context is Context, id is Id, definition is map) precondition { annotation { "Name" : "Reduction" } isInteger(definition.skip, MY_COUNT_BOUNDS); } { const data = BLOB_DATA.csvData; var str; var v; var vectors = []; var arrayCnt = 0; var totalCnt = 0; var cnt = 1; //compute total number of points and center for (var row in data) { //println('row[0] ' ~ row[0]); str = splitIntoCharacters(toString(row[0])); if (size(str) > 0 && str[0] == 'v' && str[1] == ' ') { if (cnt > definition.skip) { //println(' row[0] ' ~ row[0]); v = parseVertex(row[0]); vectors = append(vectors, v); arrayCnt += 1; cnt = 0; } totalCnt += 1; cnt += 1; } } //println('data vectors ' ~ vectors); println('total data ' ~ totalCnt); println('array data ' ~ arrayCnt); setVariable(context, 'billysVectors', vectors); setVariable(context, 'billysArrayCnt', arrayCnt); }); annotation { "Feature Type Name" : "objCenter", "UIHint" : "NO_PREVIEW_PROVIDED" } export const objCenter = defineFeature(function(context is Context, id is Id, definition is map) precondition { // Define the parameters of the feature type } { var xmax = 0; var xmin = 0; var ymax = 0; var ymin = 0; var zmax = 0; var zmin = 0; var vectorCnt = 0; var arrayCnt = getVariable(context, 'billysArrayCnt'); var vectors = getVariable(context, 'billysVectors'); //println('center vectors ' ~ vectors); //compute offset vector for (var v in vectors) { if (vectorCnt == 0) { xmax = v[0]; xmin = v[0]; ymax = v[1]; ymin = v[1]; zmax = v[2]; zmin = v[2]; } else { if (v[0] > xmax) xmax = v[0]; if (v[0] < xmin) xmin = v[0]; if (v[1] > ymax) ymax = v[1]; if (v[1] < ymin) ymin = v[1]; if (v[2] > zmax) zmax = v[2]; if (v[2] < zmin) zmin = v[2]; } vectorCnt += 1; } //println('xmax ' ~ xmax ~ ' xmin ' ~ xmin ~ ' ymax ' ~ ymax ~ ' ymin ' ~ ymin ~ ' zmax ' ~ zmax ~ ' zmax ' ~ zmax); var offsetV = vector([xmin + (xmax - xmin) / 2, ymin + (ymax - ymin) / 2, zmin + (zmax - zmin) / 2]); //println('offsetV ' ~ offsetV); //println('evDistance ' ~ evDistance (context, vectors)); for (var cnt = 0; cnt < arrayCnt; cnt += 1) { vectors[cnt] = vectors[cnt] - offsetV; } setVariable(context, 'billysVectors', vectors); println('center ' ~ arrayCnt); }, { /* default parameters */ }); export const MY_COUNT_BOUNDS2 = { "min" : 1, "max" : 1e9, (unitless) : [1, 500, 1e5] } as IntegerBoundSpec; annotation { "Feature Type Name" : "objDisplay", "UIHint" : "NO_PREVIEW_PROVIDED" } export const objDisplay = defineFeature(function(context is Context, id is Id, definition is map) precondition { // Define the parameters of the feature type annotation { "Name" : "Cloud Points" } isInteger(definition.count, MY_COUNT_BOUNDS2); } { var arrayCnt = getVariable(context, 'billysArrayCnt'); var vectors = getVariable(context, 'billysVectors'); //println('totalCnt ' ~ totalCnt); var skipNum = arrayCnt / definition.count; var skipCnt = 0; var pointCnt = 0; //display points for (var v in vectors) { //print(skipCnt ~ ' '); if (skipCnt > skipNum) { //println(pointCnt ~ ' ' ~ v); opPoint(context, id + pointCnt + "point", { "point" : v * meter, "origin" : true }); pointCnt += 1; skipCnt = 0; } skipCnt += 1; } println('display ' ~ pointCnt); }, { /* default parameters */ }); export const MY_LENGTH_BOUNDS = { "min" : -TOLERANCE.zeroLength * meter, "max" : 500 * meter, (meter) : [1e-5, 0.010, 500], (centimeter) : .05, (millimeter) : .5, (inch) : .01, (foot) : 0.001, (yard) : 0.0001 } as LengthBoundSpec; annotation { "Feature Type Name" : "objSlice", "UIHint" : "NO_PREVIEW_PROVIDED" } export const objSlice = defineFeature(function(context is Context, id is Id, definition is map) precondition { annotation { "Name" : "Pick Face", "Filter" : EntityType.FACE } definition.faces is Query; annotation { "Name" : "Tolerance Gap" } isLength(definition.gap, MY_LENGTH_BOUNDS); } { var dist = 0; var pointCnt = 0; var vectors = getVariable(context, 'billysVectors'); const faces = evaluateQuery(context, definition.faces); for (var v in vectors) { for (var face in faces) { dist = evDistance(context, { "side0" : v * meter, "side1" : face }).distance; //println('dist ' ~ dist.value); if (abs(dist.value) * meter < definition.gap) { //println(pointCnt ~ ' ' ~ v); //println('dist ' ~ dist.value); opPoint(context, id + pointCnt + "point", { "point" : v * meter, "origin" : true }); pointCnt += 1; } } } println('slice ' ~ pointCnt); }, { /* default parameters */ }); annotation { "Feature Type Name" : "objRemove", "UIHint" : "NO_PREVIEW_PROVIDED" } export const objRemove = defineFeature(function(context is Context, id is Id, definition is map) precondition { annotation { "Name" : "Pick Bodies", "Filter" : EntityType.BODY } definition.bodies is Query; //annotation { "Name" : "Tolerance Gap" } //isLength(definition.gap, MY_LENGTH_BOUNDS); annotation { "Name" : "keep points in body", "Default" : true } definition.keepPoints is boolean; } { var result = []; var pointCnt = 0; //var removeCnt = 0; var vectors = getVariable(context, 'billysVectors'); const bodies = evaluateQuery(context, definition.bodies); for (var v in vectors) { for (var body in bodies) { /* result = evCollision(context, { "tools" : v * meter, "targets" : body }); */ if (definition.keepPoints) { //outside body if (evaluateQuery(context, qContainsPoint(body, v * meter)) != []) { pointCnt += 1; //println('false '); result = append(result, v); } } else { //inside body if (evaluateQuery(context, qContainsPoint(body, v * meter)) == []) { pointCnt += 1; //println('true '); result = append(result, v); } } } } println('remove ' ~ pointCnt); //println('result' ~ result); setVariable(context, 'billysArrayCnt', pointCnt); setVariable(context, 'billysVectors', result); }, { /* default parameters */ });
oh yeah! remember to create block 1st & then paste into it. Thanks Jake.
6
Answers
I want to loop through all the vertexes in the mesh using featurescript.
There is no direct way to iterate through every single point in a mesh in FeatureScript. A user may select individual mesh points into a query parameter, but not all at once. If you are looking to do mathematical calculations on every single point, FeatureScript may simply not be the right solution for you.
We do support many ways of identifying specific positions on a mesh surface. For instance you can find the closest point to another point/plane/body with evDistance, or find a point along a ray with evRaycast.
So, what's your use case?
We don't expose mesh vertices to FeatureScript. If you do a qOwnedByBody on a mesh, you'll notice that a mesh is basically just one composite face:
https://cad.onshape.com/documents/f8b3df73f921b5ed6b03e0a3/w/180340618b58cdd57349a22f/e/899f59ff6132240c25fb70df
This simplification allows us to increase user performance when working with meshes. Please submit an Improvement Request for us to expose this information, or to create some kind of workaround function to expose a list of the locations of the vertices.
What is your desired feature here? Maybe we can suggest a different approach.
If you can get point coordinates as csv file this feature can be used to build a spline
https://cad.onshape.com/documents/a5566bc4a7c123d4958fd925/w/de9e3b016a0232b5b8ec183d/e/97994fc552ad661c4611715d
then go to the next plane. So I agree, I can use the extracted points from a csv. But it would have been so much easier to query for all the points.
Sorry for the late post, haven't had the time to dig up an old project I've worked on. I was working on point clouds and selecting planar points from cloud. I also had points close to faces. I also have an opinion about all this.
Cloud of points read from obj file:
points close to a plane:
You iterate through cloud and evaluate distance from plane to point. I think these are 1mm close to this plane. If you wanted all points on the plane, then you would have 0 points, mathematically no points are on the plane. You could project points onto the plane and then try and create a spline. Please keep in mind that these are an unsorted list and to create a spline you're going sort points from top to bottom. Then you'll end up with a crappy looking curve.
Then I asked for points closest to some faces:
I don't know what you'd do with these?
I have the code and would be happy to share it with you if you want it. The command you're looking for is eval distance.
My opinion:
I don't think it's practical to expect some algorithm to look at all the chaos in a cloud of points and come up with some geometry that'll be worth any thing. I'm no mathematician, and possibly you are, but I found this to be a dead end road.
What's working for me, is to bring in a mesh and use it as a visual guide:
It's so easy for a human to fit a spline through some chaotic point cloud and get a great shape.
Once again this my opinion, but I think an art student from your local community collage can out perform a $1,000,000 computer algorithm trying to do the same thing.
if you could send that code to tom@berry.org I am very interested.
oh yeah! remember to create block 1st & then paste into it. Thanks Jake.
The code block should be fine as long as you create the code block first and then paste into it. If you paste and then highlight and click code, it looks bad.