improve slope stuff
This commit is contained in:
parent
d72c232bf9
commit
ffc37cc636
1 changed files with 112 additions and 5 deletions
|
@ -1,5 +1,7 @@
|
|||
import re
|
||||
|
||||
from shapely.affinity import scale
|
||||
from shapely.geometry import LineString, Point
|
||||
from shapely.ops import unary_union
|
||||
|
||||
from c3nav.mapdata.render.engines import register_engine
|
||||
|
@ -46,7 +48,7 @@ class BlenderEngine(Base3DEngine):
|
|||
bpy.ops.mesh.select_all(action='SELECT')
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
|
||||
def subtract_object(obj, other_obj):
|
||||
def subtract_object(obj, other_obj, delete_after=False):
|
||||
select_object(obj)
|
||||
bpy.ops.object.modifier_add(type='BOOLEAN')
|
||||
mod = obj.modifiers
|
||||
|
@ -54,6 +56,25 @@ class BlenderEngine(Base3DEngine):
|
|||
mod[0].operation = 'DIFFERENCE'
|
||||
mod[0].object = other_obj
|
||||
bpy.ops.object.modifier_apply(apply_as='DATA', modifier=mod[0].name)
|
||||
bpy.ops.object.mode_set(mode='EDIT')
|
||||
bpy.ops.mesh.normals_make_consistent()
|
||||
triangulate_object(obj)
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
if delete_after:
|
||||
delete_object(other_obj)
|
||||
|
||||
def join_objects(objs):
|
||||
obj = objs[0]
|
||||
other_objs = objs[1:]
|
||||
for other_obj in other_objs:
|
||||
select_object(obj)
|
||||
bpy.ops.object.modifier_add(type='BOOLEAN')
|
||||
mod = obj.modifiers
|
||||
mod[0].name = 'UNion'
|
||||
mod[0].operation = 'UNION'
|
||||
mod[0].object = other_obj
|
||||
bpy.ops.object.modifier_apply(apply_as='DATA', modifier=mod[0].name)
|
||||
delete_object(other_obj)
|
||||
|
||||
def delete_object(obj):
|
||||
select_object(obj)
|
||||
|
@ -66,8 +87,8 @@ class BlenderEngine(Base3DEngine):
|
|||
exterior = add_ring(name, exterior, minz, maxz)
|
||||
for i, interior_coords in enumerate(interiors):
|
||||
interior = add_ring('%s interior %d' % (name, i), interior_coords, minz-1, maxz+1)
|
||||
subtract_object(exterior, interior)
|
||||
delete_object(interior)
|
||||
subtract_object(exterior, interior, delete_after=True)
|
||||
return exterior
|
||||
|
||||
def add_ring(name, coords, minz, maxz):
|
||||
if coords[0] == coords[-1]:
|
||||
|
@ -93,6 +114,36 @@ class BlenderEngine(Base3DEngine):
|
|||
extrude_object(obj, maxz-minz)
|
||||
|
||||
return obj
|
||||
|
||||
def add_polygon_3d(name, coords, extrude):
|
||||
if coords[0] == coords[-1]:
|
||||
coords = coords[:-1]
|
||||
if len(coords) < 3:
|
||||
raise ValueError('Ring with less than 3 points.')
|
||||
|
||||
if bpy.context.object:
|
||||
bpy.ops.object.mode_set(mode='OBJECT')
|
||||
deselect_all()
|
||||
|
||||
# create ring
|
||||
indices = tuple(range(len(coords)))
|
||||
mesh = bpy.data.meshes.new(name=name)
|
||||
mesh.from_pydata(
|
||||
coords,
|
||||
tuple(zip(indices, indices[1:]+(0, ))),
|
||||
(indices, ),
|
||||
)
|
||||
|
||||
# add ring to scene
|
||||
obj = bpy.data.objects.new(name, mesh)
|
||||
scene = bpy.context.scene
|
||||
scene.objects.link(obj)
|
||||
|
||||
## extrude it
|
||||
extrude_object(obj, extrude)
|
||||
return obj
|
||||
|
||||
polygons_for_join = []
|
||||
''')
|
||||
|
||||
def _clean_python(self, code):
|
||||
|
@ -126,14 +177,26 @@ class BlenderEngine(Base3DEngine):
|
|||
|
||||
for altitudearea in geoms.altitudeareas:
|
||||
name = 'Level %s Altitudearea %s' % (geoms.short_label, altitudearea.altitude)
|
||||
self._add_polygon(name, altitudearea.geometry.geom, min_altitude-1, altitudearea.altitude)
|
||||
if altitudearea.altitude2 is not None:
|
||||
min_slope_altitude = min(altitudearea.altitude, altitudearea.altitude2)
|
||||
max_slope_altitude = max(altitudearea.altitude, altitudearea.altitude2)
|
||||
self._add_polygon(name, altitudearea.geometry.geom, min_slope_altitude-200, max_slope_altitude)
|
||||
bounds = altitudearea.geometry.geom.bounds
|
||||
self._add_slope(bounds, altitudearea.altitude, altitudearea.altitude2,
|
||||
altitudearea.point1, altitudearea.point2)
|
||||
self._subtract_slope()
|
||||
# replace this by limiting the slope instead
|
||||
self._add_polygon(name, altitudearea.geometry.geom, min_altitude-700, min_slope_altitude)
|
||||
else:
|
||||
self._add_polygon(name, altitudearea.geometry.geom, min_altitude-700, altitudearea.altitude)
|
||||
|
||||
break
|
||||
|
||||
def _add_polygon(self, name, geometry, minz, maxz):
|
||||
geometry = geometry.buffer(0)
|
||||
for polygon in assert_multipolygon(geometry):
|
||||
self._add_python(
|
||||
'add_polygon(name=%(name)r, exterior=%(exterior)r, interiors=%(interiors)r, '
|
||||
'last_polygon = add_polygon(name=%(name)r, exterior=%(exterior)r, interiors=%(interiors)r, '
|
||||
'minz=%(minz)f, maxz=%(maxz)f)' % {
|
||||
'name': name,
|
||||
'exterior': tuple(polygon.exterior.coords),
|
||||
|
@ -143,5 +206,49 @@ class BlenderEngine(Base3DEngine):
|
|||
}
|
||||
)
|
||||
|
||||
def _add_slope(self, bounds, altitude1, altitude2, point1, point2):
|
||||
altitude_diff = altitude2-altitude1
|
||||
altitude_middle = (altitude1+altitude2)/2
|
||||
altitude_halfdiff = altitude_diff/2
|
||||
altitude_base = altitude1
|
||||
line = LineString([point1, point2])
|
||||
|
||||
minx, miny, maxx, maxy = bounds
|
||||
points_2d = [(minx-100, miny-100), (maxx+100, miny-100), (maxx+100, maxy+100), (minx-100, maxy+100)]
|
||||
points_3d = []
|
||||
for i, (x, y) in enumerate(points_2d):
|
||||
point = Point((x, y))
|
||||
pos = line.project(point)
|
||||
while pos <= 0 or pos >= line.length-1:
|
||||
line = scale(line, xfact=2, yfact=2, zfact=2)
|
||||
altitude_diff *= 2
|
||||
altitude_halfdiff *= 2
|
||||
altitude_base = altitude_middle-altitude_halfdiff
|
||||
pos = line.project(point)
|
||||
z = ((pos/line.length)*altitude_diff)+altitude_base
|
||||
points_3d.append((x, y, z/1000))
|
||||
|
||||
self._add_python(
|
||||
'last_slope = add_polygon_3d(name=%(name)r, coords=%(coords)r, extrude=%(extrude)f)' % {
|
||||
'name': 'tmpslope',
|
||||
'coords': tuple(points_3d),
|
||||
'extrude': abs(altitude1-altitude2)/1000+1,
|
||||
}
|
||||
)
|
||||
|
||||
def _subtract_slope(self):
|
||||
self._add_python('subtract_object(last_polygon, last_slope, delete_after=True)')
|
||||
|
||||
def _collect_last_polygon_for_join(self):
|
||||
self._add_python('polygons_for_join.append(last_polygon)')
|
||||
|
||||
def _clear_polygons_for_join(self):
|
||||
self._add_python('polygons_for_join = []')
|
||||
|
||||
def _join_polygons(self):
|
||||
self._add_python('join_objects(polygons_for_join)')
|
||||
self._add_python('last_polygon = polygons_for_join[0]')
|
||||
self._clear_polygons_for_join()
|
||||
|
||||
def render(self, filename=None):
|
||||
return self.result.encode()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue