Closed ArpegorPSGH closed 2 weeks ago
Good idea :) It's just a question of someone finding time to implement.
So could you label this issue as a proposal?
@ArpegorPSGH another approach (which may be faster than converting to Solid) is to use a combination of
a Vector P Field
node and a Point inside Mesh
node.
https://github.com/nortikin/sverchok/blob/master/docs/nodes/analyzer/points_inside_mesh.rst
creating a moderately sized homogenousely spaced vector field is not necessarily a low computation operation, finding if points are inside or outside a mesh is more bruteforce but computation time will depend on complexity of shapemesh and point density of the field.
Well, I already circumvented it, but not elegantly, by generating my points inside a very simple mesh converted to solid, then filtrating with points inside mesh. However, I cannot know how many points I get in the end, I can just compare it to the target, and then regenerate more points to get closer. Being able to get the exact number of points in one pass is what I would like to do.
Being able to get the exact number of points in one pass is what I would like to do
in all likelyhood the operation you describe is relatively heavy. To set a desired number of "inside mesh" points, that might involve an iterative process. (a complex volume will be heavier)
I don't think there is a need for multiple passes, as the node shouldn't start at one extremity of the volume, but instead just generate one point at a time, following the scalar field distribution limited by the mesh bounding box, then if the point is inside, it is accepted, if not it is rejected. So, each point is calculated only once.
in that case i look forward to seeing the solution :)
The algorithm is not very simple, but not too complicated also. https://github.com/nortikin/sverchok/blob/6291c91cc9fb2b90330321262a05695a593471fd/utils/field/probe.py#L40
Points are generated in bunches, not one-by-one, in order to effectively use numpy vectorization, which is implemented in many scalar field classes.
Well, the principle is te same, but indeed using numpy great vectorization performance is more efficient.
@portnov something like
"""
>in shape_v v
>in shape_f s
in count s d=50 n=2
out verts v
"""
from sverchok.utils.field.probe import field_random_probe
from sverchok.utils.field.scalar import SvBvhAttractorScalarField
from sverchok.nodes.analyzer.bbox_mk3 import bounding_box
from sverchok.utils.sv_mesh_utils import point_inside_mesh
from sverchok.utils.bvh_tree import bvh_tree_from_polygons
for geom in zip(shape_v, shape_f):
bbox = bounding_box([geom[0]],
box_dimensions='3D',
output_verts=False,
output_mat=False,
output_mean=False,
output_limits=True)
field = SvBvhAttractorScalarField(verts=geom[0], faces=geom[1]) # ?
# bbox: nested tuple: ((min_x, min_y, min_z), (max_x, max_y, max_z))
n_bbox = tuple(((bbox[4][0][0], bbox[5][0][0], bbox[6][0][0]), (bbox[7][0][0], bbox[8][0][0], bbox[9][0][0])))
new_points, _ = field_random_probe(field, n_bbox, count) #,
# threshold=0, proportional=False, field_min=None, field_max=None,
# min_r=0, min_r_field=None,
# random_radius = False,
# seed=0, predicate=None)
bvh = bvh_tree_from_polygons(geom[0], geom[1], all_triangles=False, epsilon=0.0, safe_check=True)
points = [p for p in new_points if point_inside_mesh(bvh, p)]
verts.append(points)
@zeffii you can pass lambda p: point_inside_mesh(bvh, p)
as predicate
parameter to field_random_probe
. It will be a bit faster, as you remove another pass through all points.
And obviously you can use any other scalar field.
@portnov sweet :) cobbling this together was relatively painless.
something like
"""
>in shape_v v
>in shape_f s
in count s d=50 n=2
out verts v
"""
from sverchok.utils.field.probe import field_random_probe
from sverchok.utils.field.scalar import SvBvhAttractorScalarField
from sverchok.nodes.analyzer.bbox_mk3 import bounding_box
from sverchok.utils.sv_mesh_utils import point_inside_mesh
from sverchok.utils.bvh_tree import bvh_tree_from_polygons
for geom in zip(shape_v, shape_f):
bbox = bounding_box(
[geom[0]],
box_dimensions='3D', output_verts=False, output_mat=False, output_mean=False,
output_limits=True)
co = lambda n: bbox[n][0][0]
# ((min_x, min_y, min_z), (max_x, max_y, max_z))
n_bbox = ((co(4), co(5), co(6)), (co(7), co(8), co(9)))
field = SvBvhAttractorScalarField(verts=geom[0], faces=geom[1])
bvh = bvh_tree_from_polygons(geom[0], geom[1], all_triangles=False, epsilon=0.0, safe_check=True)
points, _ = field_random_probe(field, n_bbox, count, predicate=lambda p: point_inside_mesh(bvh, p))
verts.append(points)
There is also bounding_box
method in sverchok.utils.geom
.
ok. perfect. @portnov
"""
>in shape_v v
>in shape_f s
in count s d=50 n=2
out out_verts v
"""
# - number of points are not guaranteed
# - points created as uniform random, not homogenous (reasonably equidistant from other points)
from sverchok.utils.field.probe import field_random_probe
from sverchok.utils.sv_mesh_utils import point_inside_mesh as pim
from sverchok.utils.field.scalar import SvBvhAttractorScalarField as Field
from sverchok.utils.bvh_tree import bvh_tree_from_polygons as bvh_tree
from sverchok.utils.geom import bounding_box
for verts, faces in zip(shape_v, shape_f):
bbox = bounding_box(verts)
field = Field(verts=verts, faces=faces)
bvh = bvh_tree(verts, faces, all_triangles=False, epsilon=0.0, safe_check=True)
points, _ = field_random_probe(field, (bbox.min, bbox.max), count, predicate=lambda p: pim(bvh, p))
out_verts.append(points)
but isn't this kind of ...very much... like
If you replace the scalar field with another one, the result can be very much unlike :)
"""
>in shape_v v
>in shape_f s
in field_in SF
in threshold_in s
in count s d=50 n=2
out out_verts v
"""
from sverchok.utils.field.probe import field_random_probe
from sverchok.utils.sv_mesh_utils import point_inside_mesh as pim
from sverchok.utils.bvh_tree import bvh_tree_from_polygons as bvh_tree
from sverchok.utils.geom import bounding_box
for verts, faces, field, threshold in zip(shape_v, shape_f, field_in, threshold_in):
bbox = bounding_box(verts)
bvh = bvh_tree(verts, faces, all_triangles=False, epsilon=0.0, safe_check=True)
points, _ = field_random_probe(field,
(bbox.min, bbox.max), count,
threshold = threshold[0],
predicate=lambda p: pim(bvh, p))
out_verts.append(points)
yet another field, with the same script.
yes! i see. many possibilities
Great. Now could it be possible to add a distance parameter to set a minimum distance between points, and to merge that functionalities in the Random Points on Mesh Node?
with a distance parameter, the "number of points" becomes a function of the minimum distance
.
a merge by distance
post processing step would achieve this ( as a cheap solution, otherwise the process is iterative and more computationally intense as i suggest above)
"""
>in shape_v v
>in shape_f s
in count s d=50 n=2
in min_distance s d=0.10 n=2
out out_verts v
"""
import bmesh
from sverchok.utils.field.probe import field_random_probe
from sverchok.utils.sv_mesh_utils import point_inside_mesh as pim
from sverchok.utils.field.scalar import SvBvhAttractorScalarField as Field
from sverchok.utils.bvh_tree import bvh_tree_from_polygons as bvh_tree
from sverchok.utils.geom import bounding_box
for verts, faces in zip(shape_v, shape_f):
bbox = bounding_box(verts)
field = Field(verts=verts, faces=faces)
bvh = bvh_tree(verts, faces, all_triangles=False, epsilon=0.0, safe_check=True)
points, _ = field_random_probe(field, (bbox.min, bbox.max), count, predicate=lambda p: pim(bvh, p))
bm = bmesh_from_pydata(points, [], [])
bm_verts = bm.verts
bmesh.ops.remove_doubles(bm, verts=bm_verts, dist=min_distance)
sparse_verts, _, _ = pydata_from_bmesh(bm)
out_verts.append(sparse_verts or points)
Do you get the exact number wanted with that? Also, adding a min distance does not mean discarding the scalar field, it should still be used for generating points.
@zeffii
In field_random_probe
function, you can provide min_r or min_r_field parameter.
Do you get the exact number wanted with that?
maybe i'm being thick here, but the exact number of points is a function of point distance and vice versa
@portnov
"""
>in shape_v v
>in shape_f s
in count s d=50 n=2
in min_distance s d=0.10 n=2
out out_verts v
"""
import bmesh
from sverchok.utils.field.probe import field_random_probe
from sverchok.utils.sv_mesh_utils import point_inside_mesh as pim
from sverchok.utils.field.scalar import SvBvhAttractorScalarField as Field
from sverchok.utils.bvh_tree import bvh_tree_from_polygons as bvh_tree
from sverchok.utils.geom import bounding_box
for verts, faces in zip(shape_v, shape_f):
bbox = bounding_box(verts)
field = Field(verts=verts, faces=faces)
bvh = bvh_tree(verts, faces, all_triangles=False, epsilon=0.0, safe_check=True)
points, _ = field_random_probe(field, (bbox.min, bbox.max), count, min_r=min_distance, predicate=lambda p: pim(bvh, p))
out_verts.append(points)
nice. much simpler, but does quickly throw:
sverchok.utils.field.probe 86: Maximum number of iterations (1000) reached, stop.
Yeah, obviously, if you set high enough "minimal radius", it will be hard to find a place where you can put another point.
That error is not a problem, it just means your parameters are not realistic given your mesh. Of course, the minimal radius should be small compared to the size of your mesh and the number of points you want. It is just to not have too large a density of points where the scalar field is the highest.
That error is not a problem, it just means your parameters are not realistic given your mesh.
naturally. exactly my point. it makes little sense to have two parameters (exposed to the user) affecting a system which are in essence eachother's reciprocal.
i'm probably missing the point, but i'll bow out of this convo now :)
They are reciprocal parameters only if you consider homogeneous distribution or if you fill te entire mesh up to the maximal possible density. It definitely makes sense if you have a custom scalar field and just want to be sure you won't get any points too close to each other where the scalar field is the highest.
ahaha!!! open3d helping alot to see geometry
How does this help with our problematic?
Why I cannot install open3D on mac... python mismatch?
Traceback (most recent call last):
File "/Applications/BLENDER_31/Blender.app/Contents/Resources/3.1/scripts/modules/addon_utils.py", line 351, in enable
mod = __import__(module_name)
File "/Users/jimmygunawan/Library/Application Support/Blender/3.1/scripts/addons/sverchok-open3d-master/__init__.py", line 36, in <module>
from sverchok_open3d import icons, settings, sockets, examples, menu
File "/Users/jimmygunawan/Library/Application Support/Blender/3.1/scripts/addons/sverchok-open3d-master/settings.py", line 5, in <module>
PYPATH = bpy.app.binary_path_python
AttributeError: 'bpy.app' object has no attribute 'binary_path_python'
@enzyme69 I think it's better to open separate issue
Hi @enzyme69 Can you update Sverchok-open3d addon? It works now.
I think this can be closed now, #5146 is merged.
Could it be possible to add to the volumetric mode of Random Points on Mesh a parameterization via a scalar field, like in Popuplate Solid? It is just so slow to convert a mesh to a solid, and then back when you only need to perform one not-so-heavy operation.