|
32 | 32 | from ansys.mapdl.core.inline_functions import Query |
33 | 33 | from ansys.mapdl.core.misc import ( |
34 | 34 | Information, |
| 35 | + allow_pickable_points, |
35 | 36 | last_created, |
36 | 37 | load_file, |
37 | 38 | random_string, |
38 | 39 | run_as_prep7, |
39 | 40 | supress_logging, |
| 41 | + wrap_point_SEL, |
40 | 42 | ) |
41 | 43 | from ansys.mapdl.core.plotting import general_plotter |
42 | 44 | from ansys.mapdl.core.post import PostProcessing |
@@ -3276,3 +3278,207 @@ def dim( |
3276 | 3278 | return super().dim( |
3277 | 3279 | par, type_, imax, jmax, kmax, var1, var2, var3, csysid, **kwargs |
3278 | 3280 | ) |
| 3281 | + |
| 3282 | + def _get_selected_(self, entity): # pragma: no cover |
| 3283 | + """Get list of selected entities.""" |
| 3284 | + allowed_values = ["NODE", "ELEM", "KP", "LINE", "AREA", "VOLU"] |
| 3285 | + if entity.upper() not in allowed_values: |
| 3286 | + raise ValueError( |
| 3287 | + f"The value '{entity}' is not allowed." |
| 3288 | + f"Only {allowed_values} are allowed" |
| 3289 | + ) |
| 3290 | + |
| 3291 | + entity = entity.upper() |
| 3292 | + |
| 3293 | + if entity == "NODE": |
| 3294 | + return self.mesh.nnum.copy() |
| 3295 | + elif entity == "ELEM": |
| 3296 | + return self.mesh.enum.copy() |
| 3297 | + elif entity == "KP": |
| 3298 | + return self.geometry.knum |
| 3299 | + elif entity == "LINE": |
| 3300 | + return self.geometry.lnum |
| 3301 | + elif entity == "AREA": |
| 3302 | + return self.geometry.anum |
| 3303 | + elif entity == "VOLU": |
| 3304 | + return self.geometry.vnum |
| 3305 | + |
| 3306 | + def _pick_points(self, entity, pl, type_, previous_picked_points, **kwargs): |
| 3307 | + """Show a plot and get the selected points.""" |
| 3308 | + _debug = kwargs.pop("_debug", False) # for testing purposes |
| 3309 | + previous_picked_points = set(previous_picked_points) |
| 3310 | + |
| 3311 | + q = self.queries |
| 3312 | + picked_points = [] |
| 3313 | + picked_ids = [] |
| 3314 | + |
| 3315 | + selector = getattr(q, entity.lower()) |
| 3316 | + |
| 3317 | + # adding selection inversor |
| 3318 | + pl._inver_mouse_click_selection = False |
| 3319 | + |
| 3320 | + selection_text = { |
| 3321 | + "S": "New selection", |
| 3322 | + "A": "Adding to selection", |
| 3323 | + "R": "Reselecting from the selection", |
| 3324 | + "U": "Unselecting", |
| 3325 | + } |
| 3326 | + |
| 3327 | + def gen_text(picked_points=None): |
| 3328 | + """Generate helpful text for the render window.""" |
| 3329 | + sel_ = "Unselecting" if pl._inver_mouse_click_selection else "Selecting" |
| 3330 | + type_text = selection_text[type_] |
| 3331 | + text = ( |
| 3332 | + f"Please use the left mouse button to pick the {entity}s.\n" |
| 3333 | + f"Press the key 'u' to change between mouse selecting and unselecting.\n" |
| 3334 | + f"Type: {type_} - {type_text}\n" |
| 3335 | + f"Mouse selection: {sel_}\n" |
| 3336 | + ) |
| 3337 | + |
| 3338 | + picked_points_str = "" |
| 3339 | + if picked_points: |
| 3340 | + # reverse picked point order, exclude the brackets, and limit |
| 3341 | + # to 40 characters |
| 3342 | + picked_points_str = str(picked_points[::-1])[1:-1] |
| 3343 | + if len(picked_points_str) > 40: |
| 3344 | + picked_points_str = picked_points_str[:40] |
| 3345 | + idx = picked_points_str.rfind(",") + 2 |
| 3346 | + picked_points_str = picked_points_str[:idx] + "..." |
| 3347 | + |
| 3348 | + return text + f"Current {entity} selection: {picked_points_str}" |
| 3349 | + |
| 3350 | + def callback_(mesh, id_): |
| 3351 | + point = mesh.points[id_] |
| 3352 | + node_id = selector( |
| 3353 | + point[0], point[1], point[2] |
| 3354 | + ) # This will only return one node. Fine for now. |
| 3355 | + |
| 3356 | + if not pl._inver_mouse_click_selection: |
| 3357 | + # Updating MAPDL points mapping |
| 3358 | + if node_id not in picked_points: |
| 3359 | + picked_points.append(node_id) |
| 3360 | + # Updating pyvista points mapping |
| 3361 | + if id_ not in picked_ids: |
| 3362 | + picked_ids.append(id_) |
| 3363 | + else: |
| 3364 | + # Updating MAPDL points mapping |
| 3365 | + if node_id in picked_points: |
| 3366 | + picked_points.remove(node_id) |
| 3367 | + # Updating pyvista points mapping |
| 3368 | + if id_ in picked_ids: |
| 3369 | + picked_ids.remove(id_) |
| 3370 | + |
| 3371 | + # remov etitle and update text |
| 3372 | + pl.remove_actor("title") |
| 3373 | + pl._picking_text = pl.add_text( |
| 3374 | + gen_text(picked_points), |
| 3375 | + font_size=10, |
| 3376 | + name="_point_picking_message", |
| 3377 | + ) |
| 3378 | + if picked_ids: |
| 3379 | + pl.add_mesh( |
| 3380 | + mesh.points[picked_ids], |
| 3381 | + color="red", |
| 3382 | + point_size=10, |
| 3383 | + name="_picked_points", |
| 3384 | + pickable=False, |
| 3385 | + reset_camera=False, |
| 3386 | + ) |
| 3387 | + else: |
| 3388 | + pl.remove_actor("_picked_points") |
| 3389 | + |
| 3390 | + pl.enable_point_picking( |
| 3391 | + callback=callback_, |
| 3392 | + use_mesh=True, |
| 3393 | + show_message=gen_text(), |
| 3394 | + show_point=True, |
| 3395 | + left_clicking=True, |
| 3396 | + font_size=10, |
| 3397 | + tolerance=kwargs.get("tolerance", 0.025), |
| 3398 | + ) |
| 3399 | + |
| 3400 | + def callback_u(): |
| 3401 | + # inverting bool |
| 3402 | + pl._inver_mouse_click_selection = not pl._inver_mouse_click_selection |
| 3403 | + pl._picking_text = pl.add_text( |
| 3404 | + gen_text(picked_points), |
| 3405 | + font_size=10, |
| 3406 | + name="_point_picking_message", |
| 3407 | + ) |
| 3408 | + |
| 3409 | + pl.add_key_event("u", callback_u) |
| 3410 | + |
| 3411 | + if not _debug: # pragma: no cover |
| 3412 | + pl.show() |
| 3413 | + else: |
| 3414 | + _debug(pl) |
| 3415 | + |
| 3416 | + picked_points = set( |
| 3417 | + picked_points |
| 3418 | + ) # removing duplicates (although there should be none) |
| 3419 | + |
| 3420 | + if type_ == "S": |
| 3421 | + pass |
| 3422 | + elif type_ == "R": |
| 3423 | + picked_points = previous_picked_points.intersection(picked_points) |
| 3424 | + elif type_ == "A": |
| 3425 | + picked_points = previous_picked_points.union(picked_points) |
| 3426 | + elif type_ == "U": |
| 3427 | + picked_points = previous_picked_points.difference(picked_points) |
| 3428 | + |
| 3429 | + return list(picked_points) |
| 3430 | + |
| 3431 | + def _perform_entity_list_selection( |
| 3432 | + self, entity, selection_function, type_, item, comp, vmin, kabs |
| 3433 | + ): |
| 3434 | + """Select entities using CM, and the supplied selection function.""" |
| 3435 | + self.cm(f"__temp_{entity}s__", f"{entity}") # Saving previous selection |
| 3436 | + |
| 3437 | + # Getting new selection |
| 3438 | + for id_, each_ in enumerate(vmin): |
| 3439 | + selection_function( |
| 3440 | + self, "S" if id_ == 0 else "A", item, comp, each_, "", "", kabs |
| 3441 | + ) |
| 3442 | + |
| 3443 | + self.cm(f"__temp_{entity}s_1__", f"{entity}") |
| 3444 | + |
| 3445 | + self.cmsel("S", f"__temp_{entity}s__") |
| 3446 | + self.cmsel(type_, f"__temp_{entity}s_1__") |
| 3447 | + |
| 3448 | + # Cleaning |
| 3449 | + self.cmdele(f"__temp_{entity}s__") |
| 3450 | + self.cmdele(f"__temp_{entity}s_1__") |
| 3451 | + |
| 3452 | + @wraps(Commands.nsel) |
| 3453 | + def nsel(self, *args, **kwargs): |
| 3454 | + """Wraps previons NSEL to allow to use a list/tuple/array for vmin. |
| 3455 | +
|
| 3456 | + It will raise an error in case vmax or vinc are used too. |
| 3457 | + """ |
| 3458 | + sel_func = ( |
| 3459 | + super().nsel |
| 3460 | + ) # using super() inside the wrapped function confuses the references |
| 3461 | + |
| 3462 | + @allow_pickable_points() |
| 3463 | + @wrap_point_SEL(entity="node") |
| 3464 | + def wrapped(self, *args, **kwargs): |
| 3465 | + return sel_func(*args, **kwargs) |
| 3466 | + |
| 3467 | + return wrapped(self, *args, **kwargs) |
| 3468 | + |
| 3469 | + @wraps(Commands.ksel) |
| 3470 | + def ksel(self, *args, **kwargs): |
| 3471 | + """Wraps superclassed KSEL to allow to use a list/tuple/array for vmin. |
| 3472 | +
|
| 3473 | + It will raise an error in case vmax or vinc are used too. |
| 3474 | + """ |
| 3475 | + sel_func = ( |
| 3476 | + super().ksel |
| 3477 | + ) # using super() inside the wrapped function confuses the references |
| 3478 | + |
| 3479 | + @allow_pickable_points(entity="kp", plot_function="kplot") |
| 3480 | + @wrap_point_SEL(entity="kp") |
| 3481 | + def wrapped(self, *args, **kwargs): |
| 3482 | + return sel_func(*args, **kwargs) |
| 3483 | + |
| 3484 | + return wrapped(self, *args, **kwargs) |
0 commit comments