-
Notifications
You must be signed in to change notification settings - Fork 13
/
Copy pathosm_georeferencing.py
129 lines (109 loc) · 4.47 KB
/
osm_georeferencing.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
bl_info = {
"name": "OpenStreetMap Georeferencing",
"author": "Vladimir Elistratov <[email protected]>",
"version": (1, 0, 2),
"blender": (2, 7, 8),
"location": "View 3D > Object Mode > Tool Shelf",
"description": "OpenStreetMap based object georeferencing",
"warning": "",
"wiki_url": "https://github.com/vvoovv/blender-tools/wiki/OpenStreetMap-Georeferencing",
"tracker_url": "https://github.com/vvoovv/blender-tools/issues",
"support": "COMMUNITY",
"category": "3D View",
}
import bpy
import math
from mathutils import Vector
# see conversion formulas at
# http://en.wikipedia.org/wiki/Transverse_Mercator_projection
# and
# http://mathworld.wolfram.com/MercatorProjection.html
class TransverseMercator:
radius = 6378137.
def __init__(self, **kwargs):
# setting default values
self.lat = 0. # in degrees
self.lon = 0. # in degrees
self.k = 1. # scale factor
for attr in kwargs:
setattr(self, attr, kwargs[attr])
self.latInRadians = math.radians(self.lat)
def fromGeographic(self, lat, lon):
lat = math.radians(lat)
lon = math.radians(lon-self.lon)
B = math.sin(lon) * math.cos(lat)
x = 0.5 * self.k * self.radius * math.log((1.+B)/(1.-B))
y = self.k * self.radius * ( math.atan(math.tan(lat)/math.cos(lon)) - self.latInRadians )
return (x,y)
def toGeographic(self, x, y):
x = x/(self.k * self.radius)
y = y/(self.k * self.radius)
D = y + self.latInRadians
lon = math.atan(math.sinh(x)/math.cos(D))
lat = math.asin(math.sin(D)/math.cosh(x))
lon = self.lon + math.degrees(lon)
lat = math.degrees(lat)
return (lat, lon)
class OsmGeoreferencingPanel(bpy.types.Panel):
bl_space_type = "VIEW_3D"
bl_region_type = "TOOLS"
bl_context = "objectmode"
bl_category = "Geo"
bl_label = "Georeferencing"
def draw(self, context):
wm = context.window_manager
layout = self.layout
layout.row().operator("object.set_original_position")
row = layout.row()
if not (
# the original position is set
"_x" in wm and "_y" in wm and "_h" in wm and
# custom properties "lat" and "lon" are set for the active scene
"lat" in context.scene and "lon" in context.scene and
# objects belonging to the model are selected
len(context.selected_objects)>0
):
row.enabled = False
row.operator("object.do_georeferencing")
class SetOriginalPosition(bpy.types.Operator):
bl_idname = "object.set_original_position"
bl_label = "Set original position"
bl_description = "Remember original position"
def execute(self, context):
if len(context.selected_objects)==0:
self.report({"ERROR"}, "Select objects belonging to your model")
return {"FINISHED"}
wm = context.window_manager
# remember the location and orientation of the active object
o = context.scene.objects.active
wm["_x"] = o.location.x
wm["_y"] = o.location.y
wm["_h"] = o.rotation_euler[2]
return {"FINISHED"}
class DoGeoreferencing(bpy.types.Operator):
bl_idname = "object.do_georeferencing"
bl_label = "Perform georeferencing"
bl_description = "Perform georeferencing"
bl_options = {"UNDO"}
def execute(self, context):
wm = context.window_manager
scene = context.scene
o = scene.objects.active
# calculationg the new position of the active object center
v = -Vector((wm["_x"], wm["_y"], o.location.z))
p = o.matrix_world * v
projection = TransverseMercator(lat=scene["lat"], lon=scene["lon"])
(lat, lon) = projection.toGeographic(p[0], p[1])
scene["lat"] = lat
scene["lon"] = lon
scene["heading"] = (o.rotation_euler[2]-wm["_h"])*180/math.pi
# restoring original objects location and orientation
bpy.ops.transform.rotate(value=-(o.rotation_euler[2]-wm["_h"]), axis=(0,0,1))
bpy.ops.transform.translate(value=-(o.location+v))
# cleaning up
del wm["_x"], wm["_y"], wm["_h"]
return {"FINISHED"}
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)