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:
Родитель
822b1cb7cc
Коммит
f7564d3805
|
@ -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()
|
||||
|
|
Загрузка…
Ссылка в новой задаче