Commit 71e96447 authored by sumpfralle's avatar sumpfralle

added support for 2D projection of 3D models

swapped behaviour of inch2mm and mm2inch buttons


git-svn-id: https://pycam.svn.sourceforge.net/svnroot/pycam/trunk@916 bbaffbd6-741e-11dd-a85d-61de82d9cad9
parent ce95f914
...@@ -7,6 +7,7 @@ Version 0.4.1 - UNRELEASED ...@@ -7,6 +7,7 @@ Version 0.4.1 - UNRELEASED
* visualize movements up to safety height properly * visualize movements up to safety height properly
* changed "simulation mode" for visualizing the machine moves * changed "simulation mode" for visualizing the machine moves
* added a very simple "pocketing" mode for 2D models * added a very simple "pocketing" mode for 2D models
* added 2D projection of 3D models
* added support for DXF feature "LWPOLYLINE" * added support for DXF feature "LWPOLYLINE"
* added a configuration setting for automatically loading a custom task settings file on startup * added a configuration setting for automatically loading a custom task settings file on startup
* the default filename extension for exported GCode files is now configurable * the default filename extension for exported GCode files is now configurable
......
...@@ -972,6 +972,7 @@ This can be useful if the imported model is technically broken (sometimes this h ...@@ -972,6 +972,7 @@ This can be useful if the imported model is technically broken (sometimes this h
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Scale the model by a factor of 25.4.</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
...@@ -984,12 +985,27 @@ This can be useful if the imported model is technically broken (sometimes this h ...@@ -984,12 +985,27 @@ This can be useful if the imported model is technically broken (sometimes this h
<property name="visible">True</property> <property name="visible">True</property>
<property name="can_focus">True</property> <property name="can_focus">True</property>
<property name="receives_default">True</property> <property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Scale the model by a divider of 25.4.</property>
</object> </object>
<packing> <packing>
<property name="expand">False</property> <property name="expand">False</property>
<property name="position">2</property> <property name="position">2</property>
</packing> </packing>
</child> </child>
<child>
<object class="GtkButton" id="Projection2D">
<property name="label" translatable="yes">2D Projection</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="tooltip_text" translatable="yes">Reduce the 3D model down to a 2D projection.
The projection plane is usually at z=0. Only in case of models completely above or below zero the bottom of the model is used instead.</property>
</object>
<packing>
<property name="expand">False</property>
<property name="position">3</property>
</packing>
</child>
</object> </object>
</child> </child>
</object> </object>
......
...@@ -239,7 +239,7 @@ class Model(BaseModel): ...@@ -239,7 +239,7 @@ class Model(BaseModel):
return self._t_kdtree.Search(minx, maxx, miny, maxy) return self._t_kdtree.Search(minx, maxx, miny, maxy)
return self._triangles return self._triangles
def get_waterline_polygons(self, plane): def get_waterline_contour(self, plane):
collision_lines = [] collision_lines = []
for t in self._triangles: for t in self._triangles:
collision_line = plane.intersect_triangle(t, counter_clockwise=True) collision_line = plane.intersect_triangle(t, counter_clockwise=True)
...@@ -252,7 +252,7 @@ class Model(BaseModel): ...@@ -252,7 +252,7 @@ class Model(BaseModel):
log.debug("Waterline: %f - %d - %s" % (plane.p.z, log.debug("Waterline: %f - %d - %s" % (plane.p.z,
len(contour.get_polygons()), len(contour.get_polygons()),
[len(p.get_lines()) for p in contour.get_polygons()])) [len(p.get_lines()) for p in contour.get_polygons()]))
return contour.get_polygons() return contour
def get_flat_areas(self, min_area=None): def get_flat_areas(self, min_area=None):
""" Find plane areas (combinations of triangles) bigger than 'min_area' """ Find plane areas (combinations of triangles) bigger than 'min_area'
......
...@@ -30,6 +30,8 @@ import pycam.Toolpath.Generator ...@@ -30,6 +30,8 @@ import pycam.Toolpath.Generator
import pycam.Toolpath import pycam.Toolpath
import pycam.Importers.CXFImporter import pycam.Importers.CXFImporter
import pycam.Importers import pycam.Importers
from pycam.Geometry.Point import Point, Vector
from pycam.Geometry.Plane import Plane
import pycam.Utils.log import pycam.Utils.log
import pycam.Utils import pycam.Utils
from pycam.Geometry.utils import sqrt from pycam.Geometry.utils import sqrt
...@@ -535,9 +537,11 @@ class ProjectGui: ...@@ -535,9 +537,11 @@ class ProjectGui:
self.gui.get_object("ToggleModelDirectionButton").connect("clicked", self.gui.get_object("ToggleModelDirectionButton").connect("clicked",
self.reverse_model_direction) self.reverse_model_direction)
self.gui.get_object("ScaleInchMM").connect("clicked", self.scale_model, self.gui.get_object("ScaleInchMM").connect("clicked", self.scale_model,
100 / 25.4)
self.gui.get_object("ScaleMMInch").connect("clicked", self.scale_model,
100 * 25.4) 100 * 25.4)
self.gui.get_object("ScaleMMInch").connect("clicked", self.scale_model,
100 / 25.4)
self.gui.get_object("Projection2D").connect("clicked",
self.projection_2d)
# support grid # support grid
support_grid_type_control = self.gui.get_object( support_grid_type_control = self.gui.get_object(
"SupportGridTypesControl") "SupportGridTypesControl")
...@@ -1031,6 +1035,9 @@ class ProjectGui: ...@@ -1031,6 +1035,9 @@ class ProjectGui:
and hasattr(self.model, "reverse_directions") and hasattr(self.model, "reverse_directions")
self.gui.get_object("ToggleModelDirectionButton").set_sensitive( self.gui.get_object("ToggleModelDirectionButton").set_sensitive(
is_reversible) is_reversible)
is_projectable = (not self.model is None) \
and hasattr(self.model, "get_waterline_contour")
self.gui.get_object("Projection2D").set_sensitive(is_projectable)
def update_gcode_controls(self, widget=None): def update_gcode_controls(self, widget=None):
path_mode = self.settings.get("gcode_path_mode") path_mode = self.settings.get("gcode_path_mode")
...@@ -2497,6 +2504,24 @@ class ProjectGui: ...@@ -2497,6 +2504,24 @@ class ProjectGui:
self.model.shift(new_x - old_x, new_y - old_y, new_z - old_z, self.model.shift(new_x - old_x, new_y - old_y, new_z - old_z,
callback=self.update_progress_bar) callback=self.update_progress_bar)
@progress_activity_guard
@gui_activity_guard
def projection_2d(self, widget=None):
self.update_progress_bar("Calculating 2D projection")
# determine projection plane
if (self.model.maxz < 0) or (self.model.minz > 0):
# completely above or below zero
plane_z = self.model.minz
else:
plane_z = 0
plane = Plane(Point(0, 0, plane_z), Vector(0, 0, 1))
log.info("Projecting 3D model at level z=%g" % plane_z)
projection = self.model.get_waterline_contour(plane)
if projection.get_num_of_lines() > 0:
self.load_model(projection)
else:
log.warn("The 2D projection at z=%g is empty. Aborted." % plane_z)
@progress_activity_guard @progress_activity_guard
@gui_activity_guard @gui_activity_guard
def scale_model(self, widget=None, percent=None): def scale_model(self, widget=None, percent=None):
......
...@@ -164,8 +164,8 @@ def get_support_distributed(model, z_plane, average_distance, ...@@ -164,8 +164,8 @@ def get_support_distributed(model, z_plane, average_distance,
if hasattr(model, "get_polygons"): if hasattr(model, "get_polygons"):
polygons = model.get_polygons() polygons = model.get_polygons()
else: else:
polygons = model.get_waterline_polygons(Plane(Point(0, 0, z_plane), polygons = model.get_waterline_contour(Plane(Point(0, 0, z_plane),
Vector(0, 0, 1))) Vector(0, 0, 1))).get_polygons()
bridge_positions = [] bridge_positions = []
# minimum required distance between two bridge start points # minimum required distance between two bridge start points
avoid_distance = 1.5 * (abs(length) + thickness) avoid_distance = 1.5 * (abs(length) + thickness)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment