• S sverchok
  • Информация о проекте
    • Информация о проекте
    • Активность
    • Метки
    • Участники
  • Репозиторий
    • Репозиторий
    • Файлы
    • Коммиты
    • Ветки
    • Теги
    • Участники
    • Диаграмма
    • Сравнение
  • Задачи 148
    • Задачи 148
    • Список
    • Доски
    • Спринты
  • Запросы на слияние 21
    • Запросы на слияние 21
  • CI/CD
    • CI/CD
    • Конвейеры
    • Задания
    • Расписания
  • Развертывания
    • Развертывания
    • Окружения
    • Релизы
  • Пакеты и реестры
    • Пакеты и реестры
    • Реестр пакетов
    • Реестр контейнеров
  • Мониторинг
    • Мониторинг
    • Инциденты
  • Аналитика
    • Аналитика
    • Поток ценности
    • CI/CD
    • Репозиторий
  • Wiki
    • Wiki
  • Сниппеты
    • Сниппеты
  • Активность
  • Диаграмма
  • Создать новую задачу
  • Задания
  • Коммиты
  • Доски с задачами
Свернуть панель
  • nikitronn
  • sverchok
  • Задачи
  • #2759
Закр.
Открыто
Задача созд. Дек 21, 2019 пользователемnikitronn@nikitronnВладелец

"Turtle selection" nodes? ...

Created by: portnov

Problem statement

Sometimes you want to select faces by some more or less complex algorithm. For example, select each second face. Or select one and skip two following.

But the problem is, the mesh topology can be quite complex, so there is no easy way to formulate such algorithm for an arbitrary mesh.

Solution proposal

Provide a "Turtle-style" API for mesh traversing. At each point in time, the turtle is standing at one face of the mesh and looking towards one of the face edges. It can turn to the next or to the previous edge; it can jump to the face that is beyond that edge. The thing with arbitrary mesh is that we don't know how many edges the next face will have, so where exactly should turtle look at?... Proposed solution is: after click() method, it will look at the same edge it looked before, but from another side. turn_opposite() method will turn the turtle around. If number of face edges is odd, then "opposite" direction is ambiguous; so we will have "bias" preference: whether to tend to "n / 2"th or to "n / 2 + 1"th edge. step() method is combination of click() and turn_opposite().

Such API can be used in a scripted node. As an option, we can make a special kind of scripted node for selection purposes.

An example:

import bmesh
import mathutils

from sverchok.utils.logging import debug

PREVIOUS = 'PREVIOUS'
NEXT = 'NEXT'

class Turtle(object):
    def __init__(self, bm):
        self.bmesh = bm
        self.current_face = bm.faces[0]
        self.current_loop = self.current_face.loops[0]
        self.opposite_bias = PREVIOUS
        self.visited_faces = set()

    def turn_next(self):
        self.current_loop = self.current_loop.link_loop_next

    def turn_prev(self):
        self.current_loop = self.current_loop.link_loop_prev

    def click(self):
        self.visited_faces.add(self.current_face.index)
        next_loop = self.current_loop.link_loop_radial_next
        self.current_loop = next_loop
        self.current_face = next_loop.face
        debug("Current face # := %s", self.current_face.index)

    def turn_opposite(self):
        n = len(self.current_face.loops)
        if n % 2 == 0:
            steps = n // 2
        else:
            if self.opposite_bias == 'PREVIOUS':
                steps = n // 2
            else:
                steps = n // 2 + 1
        for i in range(steps):
            self.turn_next()

    def step(self, count=1):
        for i in range(count):
            self.click()
            self.turn_opposite()

    def select(self):
        self.current_face.select = True
        debug("Selecting face #%s", self.current_face.index)

    def unselect(self):
        self.current_face.select = False
        debug("Unselecting face #%s", self.current_face.index)

    def toggle(self):
        self.current_face.select = not self.current_face.select
        debug("Set face #%s selection := %s", self.current_face.select)

    def get_selected_faces(self):
        return [[vert.index for vert in face.verts] for face in self.bmesh.faces if face.select]

    def get_selection_mask(self):
        return [face.select for face in self.bmesh.faces]

    @property
    def is_looking_at_boundary(self):
        return self.current_loop.edge.is_boundary

    @property
    def is_at_boundary(self):
        return any(edge.is_boundary for edge in self.current_face.edges)

    @property
    def was_here(self):
        return self.current_face.index in self.visited_faces
"""
in   in_verts  v
in   in_faces  s
out  out_face_mask   s
"""

from sverchok.data_structure import zip_long_repeat
from sverchok.utils.sv_bmesh_utils import bmesh_from_pydata
from sverchok.utils.turtle import Turtle

out_face_mask = []
objects = zip_long_repeat(in_verts, in_faces)
for verts, faces in objects:
    bm = bmesh_from_pydata(verts, [], faces, normal_update=True)
    bm.verts.ensure_lookup_table()
    bm.faces.ensure_lookup_table()
    turtle = Turtle(bm)
    
    #while turtle.is_looking_at_boundary:
    #    turtle.turn_next()
    turtle.turn_next()
    while True:
# Select one face, step to the following and select it too
        turtle.select()
        turtle.step()
        turtle.select()
# Make two steps in the same direction
        turtle.step(2)
# Stop if we already were here - to prevent infinite loop
        if turtle.was_here:
            break
        if turtle.is_looking_at_boundary:
            turtle.select()
            break
    
    new_face_mask = turtle.get_selection_mask()
    bm.free()
    out_face_mask.append(new_face_mask)
    print("Done")

Screenshot_20191221_223801

This example API can work with faces only; but we can make similar API for edges and vertices selection.

Ответственный
Назначить
Оценка трудозатрат