Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender-addons.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'io_import_dxf/__init__.py')
-rw-r--r--io_import_dxf/__init__.py544
1 files changed, 544 insertions, 0 deletions
diff --git a/io_import_dxf/__init__.py b/io_import_dxf/__init__.py
new file mode 100644
index 00000000..9c539634
--- /dev/null
+++ b/io_import_dxf/__init__.py
@@ -0,0 +1,544 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import bpy
+import os
+from bpy.props import StringProperty, BoolProperty, EnumProperty, IntProperty, FloatProperty
+from .dxfimport.do import Do, Indicator
+from .transverse_mercator import TransverseMercator
+
+
+try:
+ from pyproj import Proj, transform
+ PYPROJ = True
+except:
+ PYPROJ = False
+
+bl_info = {
+ "name": "Import AutoCAD DXF Format (.dxf)",
+ "author": "Lukas Treyer, Manfred Moitzi (support + dxfgrabber library), Vladimir Elistratov, Bastien Montagne",
+ "version": (0, 8, 5),
+ "blender": (2, 7, 1),
+ "location": "File > Import > AutoCAD DXF",
+ "description": "Import files in the Autocad DXF format (.dxf)",
+ "wiki_url": "https://bitbucket.org/treyerl/io_import_scene_dxf/overview",
+ "tracker_url": "https://bitbucket.org/treyerl/io_import_scene_dxf/issues?status=new&status=open",
+ "category": "Import-Export",
+}
+
+
+proj_none_items = (
+ ('NONE', "None", "No Coordinate System is available / will be set"),
+)
+proj_user_items = (
+ ('USER', "User Defined", "Define the EPSG code"),
+)
+proj_tmerc_items = (
+ ('TMERC', "Transverse Mercator", "Mercator Projection using a lat/lon coordinate as its geo-reference"),
+)
+proj_epsg_items = (
+ ('EPSG:4326', "WGS84", "World Geodetic System 84; default for lat / lon; EPSG:4326"),
+ ('EPSG:3857', "Spherical Mercator", "Webbrowser mapping service standard (Google, OpenStreetMap, ESRI); EPSG:3857"),
+ ('EPSG:27700', "National Grid U.K",
+ "Ordnance Survey National Grid reference system used in Great Britain; EPSG:27700"),
+ ('EPSG:2154', "France (Lambert 93)", "Lambert Projection for France; EPSG:2154"),
+ ('EPSG:5514', "Czech Republic & Slovakia", "Coordinate System for Czech Republic and Slovakia; EPSG:5514"),
+ ('EPSG:5243', "LLC Germany", "Projection for Germany; EPSG:5243"),
+ ('EPSG:28992', "Amersfoort Netherlands", "Amersfoort / RD New -- Netherlands; EPSG:28992"),
+ ('EPSG:21781', "Swiss CH1903 / LV03", "Switzerland and Lichtenstein; EPSG:21781"),
+ ('EPSG:5880', "Brazil Polyconic", "Cartesian 2D; Central, South America; EPSG:5880 "),
+ ('EPSG:42103', "LCC USA", "Lambert Conformal Conic Projection; EPSG:42103"),
+ ('EPSG:3350', "Russia: Pulkovo 1942 / CS63 zone C0", "Russian Federation - onshore and offshore; EPSG:3350"),
+ ('EPSG:22293', "Cape / Lo33 South Africa", "South Africa; EPSG:22293"),
+ ('EPSG:27200', "NZGD49 / New Zealand Map Grid", "NZGD49 / New Zealand Map Grid; EPSG:27200"),
+ ('EPSG:3112', "GDA94 Australia Lambert", "GDA94 / Geoscience Australia Lambert; EPSG:3112"),
+ ('EPSG:24378', "India zone I", "Kalianpur 1975 / India zone I; EPSG:24378"),
+ ('EPSG:2326', "Hong Kong 1980 Grid System", "Hong Kong 1980 Grid System; EPSG:2326"),
+ ('EPSG:3414', "SVY21 / Singapore TM", "SVY21 / Singapore TM; EPSG:3414"),
+)
+
+proj_epsg_dict = {e[0]: e[1] for e in proj_epsg_items}
+
+__version__ = '.'.join([str(s) for s in bl_info['version']])
+
+BY_LAYER = 0
+BY_DXFTYPE = 1
+SEPARATED = 2
+LINKED_OBJECTS = 3
+GROUP_INSTANCES = 4
+
+T_Merge = True
+T_ImportText = True
+T_ImportLight = True
+T_ExportAcis = False
+T_MergeLines = True
+T_OutlinerGroups = True
+T_Bbox = True
+T_CreateNewScene = False
+T_Recenter = False
+T_ThicknessBevel = False
+T_import_atts = True
+
+RELEASE_TEST = False
+DEBUG = False
+
+
+def is_ref_scene(scene):
+ return "latitude" in scene and "longitude" in scene
+
+
+def read(report, filename, obj_merge=BY_LAYER, import_text=True, import_light=True, export_acis=True, merge_lines=True,
+ do_bbox=True, block_rep=LINKED_OBJECTS, new_scene=None, recenter=False, projDXF=None, projSCN=None,
+ thicknessWidth=True, but_group_by_att=True, dxf_unit_scale=1.0):
+ # import dxf and export nurbs types to sat/sab files
+ # because that's how autocad stores nurbs types in a dxf...
+ do = Do(filename, obj_merge, import_text, import_light, export_acis, merge_lines, do_bbox, block_rep, recenter,
+ projDXF, projSCN, thicknessWidth, but_group_by_att, dxf_unit_scale)
+ errors = do.entities(os.path.basename(filename).replace(".dxf", ""), new_scene)
+
+ # display errors
+ for error in errors:
+ report('ERROR', error)
+
+ # inform the user about the sat/sab files
+ if len(do.acis_files) > 0:
+ report('INFO', "Exported %d NURBS objects to sat/sab files next to your DXF file" % len(do.acis_files))
+
+
+def display_groups_in_outliner():
+ outliners = (a for a in bpy.context.screen.areas if a.type == "OUTLINER")
+ for outliner in outliners:
+ outliner.spaces[0].display_mode = "GROUPS"
+
+
+# Update helpers (must be globals to be re-usable).
+def _update_use_georeferencing_do(self, context):
+ if not self.create_new_scene:
+ scene = context.scene
+ # Try to get Scene SRID (ESPG) data from current scene.
+ srid = scene.get("SRID", None)
+ if srid is not None:
+ self.internal_using_scene_srid = True
+ srid = srid.upper()
+ if srid == 'TMERC':
+ self.proj_scene = 'TMERC'
+ self.merc_scene_lat = scene.get('latitude', 0)
+ self.merc_scene_lon = scene.get('longitude', 0)
+ else:
+ if srid in (p[0] for p in proj_epsg_items):
+ self.proj_scene = srid
+ else:
+ self.proj_scene = 'USER'
+ self.epsg_scene_user = srid
+ else:
+ self.internal_using_scene_srid = False
+ else:
+ self.internal_using_scene_srid = False
+
+
+def _recenter_allowed(self):
+ scene = bpy.context.scene
+ return (not (self.use_georeferencing and (self.proj_scene == 'TMERC'
+ or (not self.create_new_scene and is_ref_scene(scene))))
+ or (not PYPROJ and self.dxf_indi == "EUCLIDEAN"))
+
+
+def _set_recenter(self, value):
+ self.recenter = value if _recenter_allowed(self) else False
+
+
+def _update_proj_scene_do(self, context):
+ # make sure scene EPSG is not None if DXF EPSG is not None
+ if self.proj_scene == 'NONE' and self.proj_dxf != 'NONE':
+ self.proj_scene = self.proj_dxf
+
+
+def _update_import_atts_do(self, context):
+ if self.represent_thickness_and_width and self.merge:
+ self.import_atts = True
+ elif not self.merge:
+ self.import_atts = False
+
+
+class IMPORT_OT_dxf(bpy.types.Operator):
+ """Import from DXF file format (.dxf)"""
+ bl_idname = "import_scene.dxf"
+ bl_description = 'Import from DXF file format (.dxf)'
+ bl_label = "Import DXf v." + __version__
+ bl_space_type = 'PROPERTIES'
+ bl_region_type = 'WINDOW'
+ bl_options = {'UNDO'}
+
+ filepath = StringProperty(
+ name="input file",
+ subtype='FILE_PATH'
+ )
+
+ filename_ext = ".dxf"
+
+ filter_glob = StringProperty(
+ default="*.dxf",
+ options={'HIDDEN'},
+ )
+
+ def _update_merge(self, context):
+ _update_import_atts_do(self, context)
+ merge = BoolProperty(
+ name="Merged Objects",
+ description="Merge DXF entities to Blender objects",
+ default=T_Merge,
+ update=_update_merge
+ )
+
+ merge_options = EnumProperty(
+ name="Merge",
+ description="Merge multiple DXF entities into one Blender object",
+ items=[('BY_TYPE', "By Layer AND Dxf-Type", "Merge DXF entities by type AND layer"),
+ ('BY_LAYER', "By Layer", "Merge DXF entities of a layer to an object")],
+ default='BY_LAYER',
+ )
+
+ merge_lines = BoolProperty(
+ name="Combine LINE entities to polygons",
+ description="Checks if lines are connect on start or end and merges them to a polygon",
+ default=T_MergeLines
+ )
+
+ import_text = BoolProperty(
+ name="Import Text",
+ description="Import DXF Text Entities MTEXT and TEXT",
+ default=T_ImportText,
+ )
+
+ import_light = BoolProperty(
+ name="Import Lights",
+ description="Import DXF Text Entity LIGHT",
+ default=T_ImportLight
+ )
+
+ export_acis = BoolProperty(
+ name="Export ACIS Entities",
+ description="Export Entities consisting of ACIS code to ACIS .sat/.sab files",
+ default=T_ExportAcis
+ )
+
+ outliner_groups = BoolProperty(
+ name="Display Groups in Outliner(s)",
+ description="Make all outliners in current screen layout show groups",
+ default=T_OutlinerGroups
+ )
+
+ do_bbox = BoolProperty(
+ name="Parent Blocks to Bounding Boxes",
+ description="Create a bounding box for blocks with more than one object (faster without)",
+ default=T_Bbox
+ )
+
+ block_options = EnumProperty(
+ name="Blocks As",
+ description="Select the representation of DXF blocks: linked objects or group instances",
+ items=[('LINKED_OBJECTS', "Linked Objects", "Block objects get imported as linked objects"),
+ ('GROUP_INSTANCES', "Group Instances", "Block objects get imported as group instances")],
+ default='LINKED_OBJECTS',
+ )
+
+ def _update_create_new_scene(self, context):
+ _update_use_georeferencing_do(self, context)
+ _set_recenter(self, self.recenter)
+ create_new_scene = BoolProperty(
+ name="Import DXF to new scene",
+ description="Creates a new scene with the name of the imported file",
+ default=T_CreateNewScene,
+ update=_update_create_new_scene,
+ )
+
+ recenter = BoolProperty(
+ name="Center geometry to scene",
+ description="Moves geometry to the center of the scene",
+ default=T_Recenter,
+ )
+
+ def _update_thickness_width(self, context):
+ _update_import_atts_do(self, context)
+ represent_thickness_and_width = BoolProperty(
+ name="Represent line thickness/width",
+ description="Map thickness and width of lines to Bevel objects and extrusion attribute",
+ default=T_ThicknessBevel,
+ update=_update_thickness_width
+ )
+
+ import_atts = BoolProperty(
+ name="Merge by attributes",
+ description="If 'Merge objects' is on but thickness and width are not chosen to be represented, with this "
+ "option object still can be merged by thickness, with, subd and extrusion attributes "
+ "(extrusion = transformation matrix of DXF objects)",
+ default=T_import_atts
+ )
+
+ # geo referencing
+
+ def _update_use_georeferencing(self, context):
+ _update_use_georeferencing_do(self, context)
+ _set_recenter(self, self.recenter)
+ use_georeferencing = BoolProperty(
+ name="Geo Referencing",
+ description="Project coordinates to a given coordinate system or reference point",
+ default=True,
+ update=_update_use_georeferencing,
+ )
+
+ def _update_dxf_indi(self, context):
+ _set_recenter(self, self.recenter)
+ dxf_indi = EnumProperty(
+ name="DXF coordinate type",
+ description="Indication for spherical or euclidian coordinates",
+ items=[('EUCLIDEAN', "Euclidean", "Coordinates in x/y"),
+ ('SPHERICAL', "Spherical", "Coordinates in lat/lon")],
+ default='EUCLIDEAN',
+ update=_update_dxf_indi,
+ )
+
+ # Note: FloatProperty is not precise enough, e.g. 1.0 becomes 0.999999999. Python is more precise here (it uses
+ # doubles internally), so we store it as string here and convert to number with py's float() func.
+ dxf_scale = StringProperty(
+ name="Unit Scale",
+ description="Coordinates are assumed to be in meters; deviation must be indicated here",
+ default="1.0"
+ )
+
+ def _update_proj(self, context):
+ _update_proj_scene_do(self, context)
+ _set_recenter(self, self.recenter)
+ if PYPROJ:
+ pitems = proj_none_items + proj_user_items + proj_epsg_items
+ proj_dxf = EnumProperty(
+ name="DXF SRID",
+ description="The coordinate system for the DXF file (check http://epsg.io)",
+ items=pitems,
+ default='NONE',
+ update=_update_proj,
+ )
+
+ epsg_dxf_user = StringProperty(name="EPSG-Code", default="EPSG")
+ merc_dxf_lat = FloatProperty(name="Geo-Reference Latitude", default=0.0)
+ merc_dxf_lon = FloatProperty(name="Geo-Reference Longitude", default=0.0)
+
+ pitems = proj_none_items + ((proj_user_items + proj_tmerc_items + proj_epsg_items) if PYPROJ else proj_tmerc_items)
+ proj_scene = EnumProperty(
+ name="Scn SRID",
+ description="The coordinate system for the Scene (check http://epsg.io)",
+ items=pitems,
+ default='NONE',
+ update=_update_proj,
+ )
+
+ epsg_scene_user = StringProperty(name="EPSG-Code", default="EPSG")
+ merc_scene_lat = FloatProperty(name="Geo-Reference Latitude", default=0.0)
+ merc_scene_lon = FloatProperty(name="Geo-Reference Longitude", default=0.0)
+
+ # internal use only!
+ internal_using_scene_srid = BoolProperty(default=False, options={'HIDDEN'})
+
+ def draw(self, context):
+ layout = self.layout
+ scene = context.scene
+
+ # merge options
+ layout.label("Merge Options:")
+ box = layout.box()
+ box.prop(self, "block_options")
+ box.prop(self, "do_bbox")
+ box.prop(self, "merge")
+ sub = box.row()
+ sub.enabled = self.merge
+ sub.prop(self, "merge_options")
+ box.prop(self, "merge_lines")
+
+ # general options
+ layout.label("Line thickness and width:")
+ box = layout.box()
+ box.prop(self, "represent_thickness_and_width")
+ sub = box.row()
+ sub.enabled = (not self.represent_thickness_and_width and self.merge)
+ sub.prop(self, "import_atts")
+
+ # optional objects
+ layout.label("Optional Objects:")
+ box = layout.box()
+ box.prop(self, "import_text")
+ box.prop(self, "import_light")
+ box.prop(self, "export_acis")
+
+ # view options
+ layout.label("View Options:")
+ box = layout.box()
+ box.prop(self, "outliner_groups")
+ box.prop(self, "create_new_scene")
+ sub = box.row()
+ sub.enabled = _recenter_allowed(self)
+ sub.prop(self, "recenter")
+
+ # geo referencing
+ layout.prop(self, "use_georeferencing", text="Geo Referencing:")
+ box = layout.box()
+ box.enabled = self.use_georeferencing
+ self.draw_pyproj(box, context.scene) if PYPROJ else self.draw_merc(box)
+
+ def draw_merc(self, box):
+ box.label("DXF File:")
+ box.prop(self, "dxf_indi")
+ box.prop(self, "dxf_scale")
+
+ sub = box.column()
+ sub.enabled = not _recenter_allowed(self)
+ sub.label("Geo Reference:")
+ sub = box.column()
+ sub.enabled = not _recenter_allowed(self) and self.create_new_scene
+ sub.prop(self, "merc_scene_lat", text="Lat")
+ sub.prop(self, "merc_scene_lon", text="Lon")
+
+ def draw_pyproj(self, box, scene):
+ valid_dxf_srid = True
+
+ # DXF SCALE
+ box.prop(self, "dxf_scale")
+
+ # EPSG DXF
+ box.alert = (self.proj_scene != 'NONE' and (not valid_dxf_srid or self.proj_dxf == 'NONE'))
+ box.prop(self, "proj_dxf")
+ box.alert = False
+ if self.proj_dxf == 'USER':
+ try:
+ Proj(init=self.epsg_dxf_user)
+ except:
+ box.alert = True
+ valid_dxf_srid = False
+ box.prop(self, "epsg_dxf_user")
+ box.alert = False
+
+ box.separator()
+
+ # EPSG SCENE
+ col = box.column()
+ # Only info in case of pre-defined EPSG from current scene.
+ if self.internal_using_scene_srid:
+ col.enabled = False
+
+ col.prop(self, "proj_scene")
+
+ if self.proj_scene == 'USER':
+ try:
+ Proj(init=self.epsg_scene_user)
+ except Exception as e:
+ col.alert = True
+ col.prop(self, "epsg_scene_user")
+ col.alert = False
+ col.label("") # Placeholder.
+ elif self.proj_scene == 'TMERC':
+ col.prop(self, "merc_scene_lat", text="Lat")
+ col.prop(self, "merc_scene_lon", text="Lon")
+ else:
+ col.label("") # Placeholder.
+ col.label("") # Placeholder.
+
+ # user info
+ if self.proj_scene != 'NONE':
+ if not valid_dxf_srid:
+ box.label("DXF SRID not valid", icon="ERROR")
+ if self.proj_dxf == 'NONE':
+ box.label("", icon='ERROR')
+ box.label("DXF SRID must be set, otherwise")
+ if self.proj_scene == 'USER':
+ code = self.epsg_scene_user
+ else:
+ code = self.proj_scene
+ box.label('Scene SRID %r is ignored!' % code)
+
+ def execute(self, context):
+ merge_map = {"BY_LAYER": BY_LAYER, "BY_TYPE": BY_DXFTYPE}
+ block_map = {"LINKED_OBJECTS": LINKED_OBJECTS, "GROUP_INSTANCES": GROUP_INSTANCES}
+ merge_options = SEPARATED
+ if self.merge:
+ merge_options = merge_map[self.merge_options]
+ scene = bpy.context.scene
+ if self.create_new_scene:
+ scene = bpy.data.scenes.new(os.path.basename(self.filepath).replace(".dxf", ""))
+
+ proj_dxf = None
+ proj_scn = None
+ dxf_unit_scale = 1.0
+ if self.use_georeferencing:
+ dxf_unit_scale = float(self.dxf_scale)
+ if PYPROJ:
+ if self.proj_dxf != 'NONE':
+ if self.proj_dxf == 'USER':
+ proj_dxf = Proj(init=self.epsg_dxf_user)
+ else:
+ proj_dxf = Proj(init=self.proj_dxf)
+ if self.proj_scene != 'NONE':
+ if self.proj_scene == 'USER':
+ proj_scn = Proj(init=self.epsg_scene_user)
+ elif self.proj_scene == 'TMERC':
+ proj_scn = TransverseMercator(lat=self.merc_scene_lat, lon=self.merc_scene_lon)
+ else:
+ proj_scn = Proj(init=self.proj_scene)
+ else:
+ proj_dxf = Indicator(self.dxf_indi)
+ proj_scn = TransverseMercator(lat=self.merc_scene_lat, lon=self.merc_scene_lon)
+
+ if RELEASE_TEST:
+ # for release testing
+ from . import test
+ test.test()
+ else:
+ read(self.report, self.filepath, merge_options, self.import_text, self.import_light, self.export_acis,
+ self.merge_lines, self.do_bbox, block_map[self.block_options], scene, self.recenter,
+ proj_dxf, proj_scn, self.represent_thickness_and_width, self.import_atts, dxf_unit_scale)
+
+ if self.outliner_groups:
+ display_groups_in_outliner()
+
+ return {'FINISHED'}
+
+ def invoke(self, context, event):
+ # Force first update...
+ self._update_use_georeferencing(context)
+
+ wm = context.window_manager
+ wm.fileselect_add(self)
+ return {'RUNNING_MODAL'}
+
+
+def menu_func(self, context):
+ self.layout.operator(IMPORT_OT_dxf.bl_idname, text="AutoCAD DXF")
+
+
+def register():
+ bpy.utils.register_module(__name__)
+ bpy.types.INFO_MT_file_import.append(menu_func)
+
+
+def unregister():
+ bpy.utils.unregister_module(__name__)
+ bpy.types.INFO_MT_file_import.remove(menu_func)
+
+
+if __name__ == "__main__":
+ register()