simplify and triangulate large meshes (#201)

* simplify and triangulate large meshes

* more clear logic with adding points

* apply coeff to inner rings

* fix indexError
This commit is contained in:
KatKatKateryna 2024-06-30 09:03:43 +08:00 коммит произвёл GitHub
Родитель 822b1cb7cc
Коммит f7564d3805
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
3 изменённых файлов: 59 добавлений и 29 удалений

Просмотреть файл

@ -1,4 +1,5 @@
import inspect
import math
from typing import List, Tuple, Union
from specklepy.objects.geometry import Mesh, Point
from specklepy.objects.other import RenderMaterial
@ -210,18 +211,16 @@ def meshPartsFromPolygon(
iterations = 0
coef = 1
maxPoints = 5000
maxPoints = 500
if len(polyBorder) >= maxPoints:
coef = int(len(polyBorder) / maxPoints)
coef = math.floor(len(polyBorder) / maxPoints)
if len(polyBorder) < 3:
return None, None, None, None, None
col = featureColorfromNativeRenderer(feature, layer)
if (
len(voidsAsPts) == 0
): # only if there is a mesh with no voids and large amount of points
if len(voidsAsPts) == 0: # only if there is a mesh with no voids
# floor: need positive - clockwise (looking down); cap need negative (counter-clockwise)
polyBorder = fix_orientation(polyBorder, True, coef) # clockwise
@ -229,8 +228,8 @@ def meshPartsFromPolygon(
polyBorder.reverse() # when no extrusions: face up, counter-clockwise
for k, ptt in enumerate(polyBorder): # pointList:
pt = polyBorder[k * coef]
if k < maxPoints:
pt = polyBorder[k * coef]
vertices.extend([pt.x, pt.y, pt.z])
total_vertices += 1
else:
@ -351,7 +350,7 @@ def meshPartsFromPolygon(
# get points from original geometry #################################
triangulated_geom, vertices3d_original, iterations = triangulatePolygon(
feature_geom, dataStorage, xform
feature_geom, dataStorage, coef, xform
)
# temporary solution, as the list of points is not the same anymore:

Просмотреть файл

@ -127,7 +127,9 @@ def projectToPolygon(
return z
def getPolyPtsSegments(geom: Any, dataStorage: "DataStorage", xform):
def getPolyPtsSegments(
geom: Any, dataStorage: "DataStorage", coef: Union[int, None] = None, xform=None
):
vertices = []
vertices3d = []
segmList = []
@ -145,18 +147,27 @@ def getPolyPtsSegments(geom: Any, dataStorage: "DataStorage", xform):
pt_iterator = geom.vertices()
# get boundary points and segments
pointListLocal = []
pointListLocalOuter = []
startLen = len(vertices)
for i, pt in enumerate(pt_iterator):
if (
len(pointListLocal) > 0
and pt.x() == pointListLocal[0].x()
and pt.y() == pointListLocal[0].y()
): # don't repeat 1st point
len(pointListLocalOuter) > 0
and pt.x() == pointListLocalOuter[0].x()
and pt.y() == pointListLocalOuter[0].y()
):
# don't repeat 1st point
pass
elif coef is None:
pointListLocalOuter.append(pt)
else:
pointListLocal.append(pt)
for i, pt in enumerate(pointListLocal):
if i % coef == 0:
pointListLocalOuter.append(pt)
else:
# don't add points, which are in-between specified step (coeff)
# e.g. if coeff=5, we skip ponts 1,2,3,4, but add points 0 and 5
pass
for i, pt in enumerate(pointListLocalOuter):
x, y = apply_pt_offsets_rotation_on_send(pt.x(), pt.y(), dataStorage)
vertices.append([x, y])
try:
@ -182,18 +193,29 @@ def getPolyPtsSegments(geom: Any, dataStorage: "DataStorage", xform):
pt_list = list(pt_iterator)
pointListLocal = []
startLen = len(vertices)
for i, pt in enumerate(pt_list):
if (
len(pointListLocal) > 0
and pt.x() == pointListLocal[0].x()
and pt.y() == pointListLocal[0].y()
): # don't repeat 1st point
):
# don't repeat 1st point
continue
elif [
pt.x(),
pt.y(),
] not in vertices: # in case it's not the inner part of geometry
pointListLocal.append(pt)
elif pt not in pointListLocalOuter:
# make sure it's not already included in the outer part of geometry
if coef is None or len(pt_list) / coef < 5:
# coef was calculated by the outer ring.
# We need to make sure inner ring will have at least 4 points, otherwise ignore coeff.
pointListLocal.append(pt)
else:
if i % coef == 0:
pointListLocal.append(pt)
else:
# don't add points, which are in-between specified step (coeff)
# e.g. if coeff=5, we skip ponts 1,2,3,4, but add points 0 and 5
pass
if len(pointListLocal) > 2:
holes.append(
@ -322,14 +344,14 @@ def to_triangles(data: dict, attempt: int = 0) -> Tuple[Union[dict, None], int]:
def triangulatePolygon(
geom: Any, dataStorage: "DataStorage", xform=None
geom: Any, dataStorage: "DataStorage", coef: Union[int, None] = None, xform=None
) -> Tuple[dict, Union[List[List[float]], None], int]:
try:
# import triangle as tr
vertices = [] # only outer
segments = [] # including holes
holes = []
pack = getPolyPtsSegments(geom, dataStorage, xform)
pack = getPolyPtsSegments(geom, dataStorage, coef, xform)
vertices, vertices3d, segments, holes = pack
@ -432,13 +454,20 @@ def fix_orientation(
index = k + 1
if k == len(polyBorder) - 1:
index = 0
pt = polyBorder[k * coef]
pt2 = polyBorder[index * coef]
if isinstance(pt, Point) and isinstance(pt2, Point):
sum_orientation += (pt2.x - pt.x) * (pt2.y + pt.y) # if Speckle Points
else:
sum_orientation += (pt2.x() - pt.x()) * (pt2.y() + pt.y()) # if QGIS Points
try:
pt = polyBorder[k * coef]
pt2 = polyBorder[index * coef]
if isinstance(pt, Point) and isinstance(pt2, Point):
sum_orientation += (pt2.x - pt.x) * (pt2.y + pt.y) # if Speckle Points
else:
sum_orientation += (pt2.x() - pt.x()) * (
pt2.y() + pt.y()
) # if QGIS Points
except IndexError:
break
if positive is True:
if sum_orientation < 0:
polyBorder.reverse()

Просмотреть файл

@ -595,6 +595,8 @@ def isAppliedLayerTransformByKeywords(
def getElevationLayer(dataStorage):
elevationLayer = dataStorage.elevationLayer
if elevationLayer is None:
return None
try:
# check if layer was not deleted
name = elevationLayer.name()