Exemplo n.º 1
0
    def OnKeyDown(self, e):
        k = e.GetKeyCode()
        if k == wx.WXK_UP:
            sel = cad.GetSelectedObjects()
            index = -1
            if len(sel) > 0:
                index = self.ObjectRenderedIndex(sel[-1])
                if index > 0:
                    index -= 1
            if (index == -1) and (len(self.rendered_objects) > 0):
                index = len(self.rendered_objects) - 1

            cad.ClearSelection(True)

            if len(self.rendered_objects):
                cad.Select(self.rendered_objects[index])
        elif k == wx.WXK_DOWN:
            sel = cad.GetSelectedObjects()
            index = -1
            if len(sel) > 0:
                index = self.ObjectRenderedIndex(sel[-1])
                if index < len(self.rendered_objects) - 1:
                    index += 1
            if (index == -1) and (len(self.rendered_objects) > 0):
                index = 0

            cad.ClearSelection(True)

            if len(self.rendered_objects):
                cad.Select(self.rendered_objects[index])
        else:
            wx.GetApp().OnKeyDown(e)
Exemplo n.º 2
0
    def OnSweep(self, event):
        if cad.GetNumSelected() == 0:
            self.PickObjects('Pick Some Sketches, Faces or Circles')

        if not self.CheckForNumberOrMore(
                1,
            [
                cad.OBJECT_TYPE_SKETCH,
                step.GetFaceType(), cad.OBJECT_TYPE_CIRCLE
            ], 'Pick one or more sketches, faces or circles, to sweep\n( hold down Ctrl key to select more than one solid )',
                'Sweep'):
            return

        sweep_objects = cad.GetSelectedObjects()
        cad.ClearSelection(True)
        self.PickObjects('Pick a Sketch to Sweep Along')

        if not self.CheckForNumberOrMore(1, [cad.OBJECT_TYPE_SKETCH],
                                         'Pick one sketch to sweep along',
                                         'Sweep'):
            return

        sweep_profile = cad.GetSelectedObjects()[0]

        cad.StartHistory()
        step.CreateSweep(sweep_objects, sweep_profile,
                         cad.Color(128, 150, 128))
        cad.EndHistory()
Exemplo n.º 3
0
 def SketchOperation(self, mode):
     objects_to_delete = []
     area = None
     
     for object in cad.GetSelectedObjects():
         t = object.GetType()
         if t == cad.OBJECT_TYPE_SKETCH:
             objects_to_delete.append(object)
             sketch = object
             sketch.__class__ = cad.Sketch
             a = sketch.GetArea()
             if area == None:
                 area = a
             else:
                 if mode == SKETCH_OP_UNION:
                     area.Union(a)
                 elif mode == SKETCH_OP_SUBTRACT:
                     area.Subtract(a)
                 elif mode == SKETCH_OP_INTERSECT:
                     area.Intersect(a)                         
                 
     if area != None:
         cad.StartHistory()
         sketch = cad.NewSketchFromArea(area)
         cad.AddUndoably(sketch)
         cad.DeleteObjectsUndoably(objects_to_delete)
         cad.EndHistory()
Exemplo n.º 4
0
    def GetSelectionFilterTools(self, filter):
        # get tools for the selection given filter
        tools = []

        if filter.Size() > 0:
            tools.append(ContextTool.CADContextTool('Delete Marked Items', 'delete', self.DeleteMarkedList))
                
        if self.SketchChildTypeInFilter(filter):
            tools.append(ContextTool.CADContextTool('Make to Sketch', 'makesketch', self.MakeToSketch))

        if filter.IsTypeInFilter(cad.OBJECT_TYPE_SKETCH):
            tools.append(ContextTool.CADContextTool('Combine sketches', 'sketchjoin', cad.CombineSelectedSketches))
            tools.append(ContextTool.CADContextTool('Unite sketches', 'sketchunite', self.UniteSelectedSketches))
            tools.append(ContextTool.CADContextTool('Cut sketches', 'sketchcut', self.CutSelectedSketches))
            tools.append(ContextTool.CADContextTool('Intersect sketches', 'sketchintersect', self.IntersectSelectedSketches))
        
        first_coord_sys = None
        second_coord_sys = None
        
        for object in cad.GetSelectedObjects():
            if object.GetType() == cad.OBJECT_TYPE_COORD_SYS:
                if first_coord_sys == None: first_coord_sys = object
                elif second_coord_sys == None: second_coord_sys = object

        return tools
Exemplo n.º 5
0
def OriTransform():
    if cad.GetNumSelected() == 0:
        wx.GetApp().PickObjects('Pick objects to transform')

    if cad.GetNumSelected() == 0:
        return

    config = HeeksConfig()

    selected_items = cad.GetSelectedObjects()

    cad.ClearSelection(False)

    o1 = PickOrigin('Pick From Origin')
    if o1 == None:
        wx.MessageBox("You didn't pick an origin\nTransform Cancelled!")
        return

    o2 = PickOrigin('Pick To Origin')
    if o2 == None:
        wx.MessageBox("You didn't pick an origin\nTransform Cancelled!")
        return

    cad.StartHistory()

    m1 = o1.GetOrigin()
    mat = m1.Inverse()
    m2 = o2.GetOrigin()
    mat.Multiply(m2)
    for object in selected_items:
        cad.TransformUndoably(object, mat)

    cad.EndHistory()
Exemplo n.º 6
0
def RemoveUncopyable():
    uncopyable_objects = []
    for object in cad.GetSelectedObjects():
        if not object.CanBeCopied():
            uncopyable_objects.append(object)

    for object in uncopyable_objects:
        cad.Unselect(object)
Exemplo n.º 7
0
    def PickSketch(self):
        cad.ClearSelection()
        wx.GetApp().PickObjects('Pick a sketch', cad.OBJECT_TYPE_SKETCH, True)

        self.cmbSketch.Recreate()
        self.Fit()

        id = 0
        if cad.GetNumSelected() > 0: id = cad.GetSelectedObjects()[0].GetID()
        self.cmbSketch.SelectById(id)
Exemplo n.º 8
0
def PickOrigin(prompt):
    filter = cad.Filter()
    filter.AddType(cad.OBJECT_TYPE_COORD_SYS)
    wx.GetApp().PickObjects(prompt, filter, True)
    origin = None
    for object in cad.GetSelectedObjects():
        if object.GetType() == cad.OBJECT_TYPE_COORD_SYS:
            origin = object
            break
    return origin
Exemplo n.º 9
0
def Mirror():
    if cad.GetNumSelected() == 0:
        wx.GetApp().PickObjects('Pick objects to mirror')

    if cad.GetNumSelected() == 0:
        return

    config = HeeksConfig()

    selected_items = cad.GetSelectedObjects()

    cad.ClearSelection(False)

    copy = config.ReadBool("MirrorCopy", False)
    axis = geom.Point3D(0, 0, 1)
    pos = geom.Point3D(0, 0, 0)
    axis.x = config.ReadFloat("MirrorAxisX", 1.0)
    axis.y = config.ReadFloat("MirrorAxisY", 0.0)
    axis.z = config.ReadFloat("MirrorAxisZ", 0.0)
    pos.x = config.ReadFloat("MirrorPosX", 0.0)
    pos.y = config.ReadFloat("MirrorPosY", 0.0)
    pos.z = config.ReadFloat("MirrorPosZ", 0.0)

    result, axis, pos, copy = InputMirrorPlane(axis, pos, copy, 'Mirror')
    if not result:
        return

    config.WriteBool("MirrorCopy", copy)
    config.WriteFloat("MirrorAxisX", axis.x)
    config.WriteFloat("MirrorAxisY", axis.y)
    config.WriteFloat("MirrorAxisZ", axis.z)
    config.WriteFloat("MirrorPosX", pos.x)
    config.WriteFloat("MirrorPosY", pos.y)
    config.WriteFloat("MirrorPosZ", pos.z)

    cad.StartHistory()

    mat = geom.Matrix()
    x, y = axis.ArbitraryAxes()
    axis_mat = geom.Matrix(pos, x, y)
    inv_mat = axis_mat.Inverse()
    mat.Multiply(inv_mat)  # transform so axis goes to z axis
    mat.Scale3(1.0, 1.0, -1.0)  # mirror in z axis
    mat.Multiply(axis_mat)  # transform back to where it was
    for object in selected_items:
        if copy:
            if object.CanBeCopied():
                object = object.MakeACopy()
                object.Transform(mat)
                cad.AddUndoably(object)
        else:
            cad.TransformUndoably(object, mat)

    cad.EndHistory()
Exemplo n.º 10
0
    def GetSelectionFilterTools(self, filter):
        tools = App.GetSelectionFilterTools(self, filter)

        objects = cad.GetSelectedObjects()

        if filter.IsTypeInFilter(cad.OBJECT_TYPE_SKETCH
                                 ) or self.SketchChildTypeInFilter(filter):
            tools.append(
                ContextTool.CADContextTool('Sketch to Face', 'la2face',
                                           step.SketchToFace))

        return tools
Exemplo n.º 11
0
    def NewStock(self, e):
        solids = []
        for object in cad.GetSelectedObjects():
            if object.GetIDGroupType() == cad.OBJECT_TYPE_STL_SOLID:
                solids.append(object.GetID())

        new_object = Stock.Stock()
        new_object.solids += solids
        new_object.SetID(cad.GetNextID(Stock.type))
        if new_object.Edit():
            cad.AddUndoably(new_object, self.program.stocks, None)
            self.EndHistory()
Exemplo n.º 12
0
 def CopySelectedItems(self):
     temp_file = wx.StandardPaths.Get().GetTempDir() + '/temp_Heeks_clipboard_file.xml'
     cad.SaveObjects(temp_file, cad.GetSelectedObjects())
     
     f = open(temp_file)
     s = f.read()
     
     if wx.TheClipboard.Open():
         wx.TheClipboard.SetData(wx.TextDataObject(s))
         wx.TheClipboard.Close()
         
     f.close()
Exemplo n.º 13
0
    def PickPoints(self):
        cad.ClearSelection()
        wx.GetApp().PickObjects('Pick points to drill',
                                cad.Filter(cad.OBJECT_TYPE_POINT), False)

        ids = []
        for object in cad.GetSelectedObjects():
            if object.GetType() == cad.OBJECT_TYPE_POINT:
                ids.append(object.GetID())

        self.idsPoints.SetFromIdList(ids)

        self.Fit()
Exemplo n.º 14
0
 def OnSpline(self, e):
     if not self.CheckForNumberOrMore(
             2, [cad.OBJECT_TYPE_POINT],
             'Pick one or more points to make a spline through',
             'Spline Through Points'):
         return
     cad.StartHistory()
     points = []
     for object in cad.GetSelectedObjects():
         points.append(object.GetStartPoint())
     new_object = step.NewSplineFromPoints(points)
     cad.AddUndoably(new_object)
     cad.EndHistory()
Exemplo n.º 15
0
def Scale():
    centre_Pos = geom.Point3D(0, 0, 0)

    if cad.GetNumSelected() == 0:
        wx.GetApp().PickObjects('Pick objects to scale')

    if cad.GetNumSelected() == 0:
        return

    config = HeeksConfig()

    selected_items = cad.GetSelectedObjects()

    cad.ClearSelection(False)

    scale_factor = config.ReadFloat('ScaleFactor', 1.0)
    copy = config.ReadBool("ScaleCopy", False)
    pos = geom.Point3D(0, 0, 0)
    pos.x = config.ReadFloat("ScaleAboutPosX", 0.0)
    pos.y = config.ReadFloat("ScaleAboutPosY", 0.0)
    pos.z = config.ReadFloat("ScaleAboutPosZ", 0.0)

    result, pos, scale_factor, copy = InputScale(pos, scale_factor, copy,
                                                 'Scale')
    if not result:
        return

    config.WriteFloat("ScaleFactor", scale_factor)
    config.WriteBool("ScaleCopy", copy)
    config.WriteFloat("ScaleAboutPosX", pos.x)
    config.WriteFloat("ScaleAboutPosY", pos.y)
    config.WriteFloat("ScaleAboutPosZ", pos.z)

    cad.StartHistory()

    mat = geom.Matrix()
    mat.Translate(-pos)
    mat.Scale(scale_factor)
    mat.Translate(pos)
    for object in selected_items:
        if copy:
            if object.CanBeCopied():
                object = object.MakeACopy()
                object.Transform(mat)
                cad.AddUndoably(object)
        else:
            cad.TransformUndoably(object, mat)

    cad.EndHistory()
Exemplo n.º 16
0
 def MakeToSketch(self):
     objects_to_delete = []
     sketch = cad.NewSketch()
     
     for object in cad.GetSelectedObjects():
         t = object.GetType()
         if object.CanAddTo(sketch):
             new_object = object.MakeACopy()
             objects_to_delete.append(object)
             sketch.Add(new_object)
     
     cad.StartHistory()
     cad.AddUndoably(sketch)
     cad.DeleteObjectsUndoably(objects_to_delete)
     cad.EndHistory()
Exemplo n.º 17
0
 def PickSolids(self):
     cad.ClearSelection(True)
     filter = cad.Filter()
     filter.AddType(cad.OBJECT_TYPE_STL_SOLID)
     if wx.GetApp().IsSolidApp():
         import step
         filter.AddType(step.GetSolidType())
     wx.GetApp().PickObjects('Pick solids', filter, False)
     
     solids = []
     for object in cad.GetSelectedObjects():
         if object.GetIDGroupType() == cad.OBJECT_TYPE_STL_SOLID:
             solids.append(object.GetID())
             
     self.idsSolids.SetFromIdList(solids)
     self.Fit()
Exemplo n.º 18
0
 def CheckForNumberOrMore(self, min_num, types, msg, caption):
     num_found = 0
     for object in cad.GetSelectedObjects():
         for type in types:
             if object.GetType() == type:
                 num_found += 1
                 break
             
     if num_found < min_num:
         filter = cad.Filter()
         for t in types: filter.AddType(t)
         objects = self.PickObjects(msg, filter, False)
         if cad.GetNumSelected() < min_num:
             wx.MessageBox(msg)
             return False
     return True
Exemplo n.º 19
0
 def RotateToFace(self, object):
     n = self.context_face_plane.normal
     p = n * (-self.context_face_plane.d)
     x, y = n.ArbitraryAxes()
     face_matrix = geom.Matrix(p, x, y)
     inv_matrix = face_matrix.Inverse()
     cad.StartHistory()
     selected = cad.GetSelectedObjects()
     # if any objects are selected, move them
     if len(selected) > 0:
         for object in selected:
             cad.TransformUndoably(object, inv_matrix)
     else:
         # move the solid
         parent_body = object.GetParentBody()
         cad.TransformUndoably(parent_body, inv_matrix)
     cad.EndHistory()
Exemplo n.º 20
0
 def OnShadow(self, event):
     if not self.CheckForNumberOrMore(
             1, [step.GetSolidType(), cad.OBJECT_TYPE_STL_SOLID],
             'Pick one or more solids to make a shadow sketch from',
             'Shadow Sketch of Solids'):
         return
     accuracy = self.InputLength('Enter Shadow Accuracy', 'Accuracy',
                                 geom.get_accuracy())
     if accuracy:
         cad.StartHistory()
         geom.set_accuracy(accuracy)
         for object in cad.GetSelectedObjects():
             stl = object.GetTris(accuracy)
             mat = geom.Matrix()
             shadow = stl.Shadow(mat, False)
             #shadow.Reorder()
             sketch = cad.NewSketchFromArea(shadow)
             cad.AddUndoably(sketch)
         cad.EndHistory()
Exemplo n.º 21
0
 def OnSelectionChanged(self, added, removed):
     self.window.objects = cad.GetSelectedObjects()
     #self.make_initial_properties_in_refresh = True
     self.window.RemoveAndAddAll()
Exemplo n.º 22
0
def Translate(copy=False):
    if cad.GetNumSelected() == 0:
        wx.GetApp().PickObjects('Pick objects to move')

    if cad.GetNumSelected() == 0:
        return

    config = HeeksConfig()
    ncopies = None
    if copy:
        ncopies = config.ReadInt('TranslateNumCopies', 1)
        RemoveUncopyable()
        if cad.GetNumSelected() == 0:
            return

    selected_items = cad.GetSelectedObjects()

    cad.ClearSelection(False)

    fromp = geom.Point3D()
    to = geom.Point3D()

    fromp.x = config.ReadFloat("TranslateFromX", 0.0)
    fromp.y = config.ReadFloat("TranslateFromY", 0.0)
    fromp.z = config.ReadFloat("TranslateFromZ", 0.0)
    to.x = config.ReadFloat("TranslateToX", 0.0)
    to.y = config.ReadFloat("TranslateToY", 0.0)
    to.z = config.ReadFloat("TranslateToZ", 0.0)

    result, fromp, to, ncopies = InputFromAndTo(fromp, to, ncopies,
                                                'Move Translate')
    if not result:
        return

    if copy:
        if ncopies < 1:
            return
        config.WriteInt("TranslateNumCopies", ncopies)

    config.WriteFloat("TranslateFromX", fromp.x)
    config.WriteFloat("TranslateFromY", fromp.y)
    config.WriteFloat("TranslateFromZ", fromp.z)
    config.WriteFloat("TranslateToX", to.x)
    config.WriteFloat("TranslateToY", to.y)
    config.WriteFloat("TranslateToZ", to.z)

    cad.StartHistory()

    if copy:
        for i in range(0, ncopies):
            mat = geom.Matrix()
            mat.Translate((to - fromp) * (i + 1))
            for object in selected_items:
                new_object = object.MakeACopy()
                object.GetOwner().Add(new_object)
                cad.TransformUndoably(new_object, mat)
    else:
        mat = geom.Matrix()
        mat.Translate(to - fromp)
        for object in selected_items:
            cad.TransformUndoably(object, mat)

    cad.EndHistory()
Exemplo n.º 23
0
 def GetSelectedPoints(self):
     points = []
     for object in cad.GetSelectedObjects():
         if object.GetIDGroupType() == cad.OBJECT_TYPE_POINT:
             points.append(object.GetID())
     return points
Exemplo n.º 24
0
 def GetSelectedSketches(self):
     sketches = []
     for object in cad.GetSelectedObjects():
         if object.GetIDGroupType() == cad.OBJECT_TYPE_SKETCH:
             sketches.append(object.GetID())
     return sketches
Exemplo n.º 25
0
 def DeleteMarkedList(self):
     to_delete = []
     for object in cad.GetSelectedObjects():
         if object.CanBeDeleted():
             to_delete.append(object)
     cad.DeleteObjectsUndoably(to_delete)
Exemplo n.º 26
0
 def OnCut(self, e):
     self.CopySelectedItems()
     cad.StartHistory()
     for object in cad.GetSelectedObjects():
         cad.DeleteUndoably(object)
     cad.EndHistory()
Exemplo n.º 27
0
    def OnMouse(self, event):
        # to do? if(wxGetApp().m_property_grid_validation)return;
        if event.Entering():
            self.SetFocus()  # so middle wheel works

        if event.LeftDown():
            button = self.HitTest(event.GetPosition())

            if button:
                if button.type == ButtonTypePlus or button.type == ButtonTypeMinus:
                    self.SetExpanded(button.obj, button.type == ButtonTypePlus)
                    self.SetVirtualSize(self.GetRenderSize())
                    self.Refresh()
                else:
                    self.OnLabelLeftDown(button.obj, event)
                    self.clicked_object = button.obj
            else:
                cad.ClearSelection(True)

            self.button_down_point = event.GetPosition()

        if event.LeftUp():
            if self.dragging:
                self.dragging = False

                # find the object to drop on to
                button = self.HitTest(event.GetPosition())

                if (button == None) or not cad.ObjectMarked(
                        button.obj
                ):  # can only drop on to an item other than one of the items being dragged
                    # test drop possible
                    drag_possible = True

                    add_to = cad.GetApp()
                    if button and button.paste_into: add_to = button.paste_into
                    for object in self.dragged_list:
                        if not add_to.CanAdd(object) or not object.CanAddTo(
                                add_to):
                            drag_possible = False
                            break

                    if drag_possible:
                        cad.StartHistory()

                        # cut the objects
                        cad.DeleteObjectsUndoably(self.dragged_list)

                        # paste the objects
                        for object in self.dragged_list:
                            if object.OneOfAKind():
                                one_found = False
                                child = add_to.GetFirstChild()
                                while child:
                                    if child.GetType() == object.GetType():
                                        child.CopyFrom(object)
                                        one_found = True
                                        break

                                    child = add_to.GetNextChild()

                                if not one_found:
                                    cad.AddUndoably(
                                        object, add_to, button.paste_before if
                                        (button != None) else None)
                            else:
                                cad.AddUndoably(
                                    object, add_to, button.paste_before if
                                    (button != None) else None)

                        cad.EndHistory()
                    else:
                        self.Refresh()
                else:
                    self.Refresh()
            else:
                if self.waiting_until_left_up:
                    cad.ClearSelection(False)
                    cad.Select(self.clicked_object, True)
            self.waiting_until_left_up = False

        if event.RightDown():
            button = self.HitTest(event.GetPosition())
            self.clicked_object = None
            if (button != None) and (button.type == ButtonTypeLabelBefore
                                     or button.type == ButtonTypeLabel):
                self.clicked_object = button.obj
                self.OnLabelRightDown(button.obj, event)

        if event.RightUp():
            if self.dragging:
                self.dragging = False
            else:
                tools = self.GetDropDownTools(event.ControlDown())
                menu = wx.Menu()
                for tool in tools:
                    wx.GetApp().AddToolToListAndMenu(tool, menu)
                self.PopupMenu(menu, event.GetPosition())

        if event.Dragging():
            if event.LeftIsDown() or event.RightIsDown():
                if (not self.dragging) and (
                        math.fabs(self.button_down_point.x - event.GetX()) > 2
                        or math.fabs(self.button_down_point.y - event.GetY()) >
                        2):
                    self.dragging = True
                    self.dragged_list = cad.GetSelectedObjects()

            if self.dragging:
                self.drag_position = self.CalcUnscrolledPosition(
                    event.GetPosition())
                button = self.HitTest(event.GetPosition())
                self.drag_paste_rect = wx.Rect(0, 0, 0, 0)
                if (button != None) and (button.type == ButtonTypeLabelBefore):
                    self.drag_paste_rect = button.rect
                self.Refresh()

        if event.LeftDClick():
            if self.clicked_object:
                wx.GetApp().EditUndoably(self.clicked_object)

        event.Skip()
Exemplo n.º 28
0
 def OnDelete(self, e):
     cad.StartHistory()
     for object in cad.GetSelectedObjects():
         cad.DeleteUndoably(object)
     cad.EndHistory()
Exemplo n.º 29
0
def Rotate(copy=False):
    #rotation axis - Z axis by default
    axis_Dir = geom.Point3D(0, 0, 1)
    line_Pos = geom.Point3D(0, 0, 0)

    if cad.GetNumSelected() == 0:
        wx.GetApp().PickObjects('Pick objects to rotate')

    if cad.GetNumSelected() == 0:
        return

    config = HeeksConfig()
    ncopies = None
    if copy:
        ncopies = config.ReadInt('RotateNumCopies', 1)
        RemoveUncopyable()
        if cad.GetNumSelected() == 0:
            return

    selected_items = cad.GetSelectedObjects()

    cad.ClearSelection(False)

    angle = config.ReadFloat('RotateAngle', 90.0)

    # enter angle, plane and position

    axis = geom.Point3D(0, 0, 1)
    pos = geom.Point3D(0, 0, 0)
    axis.x = config.ReadFloat("RotateAxisX", 0.0)
    axis.y = config.ReadFloat("RotateAxisY", 0.0)
    axis.z = config.ReadFloat("RotateAxisZ", 1.0)
    pos.x = config.ReadFloat("RotatePosX", 0.0)
    pos.y = config.ReadFloat("RotatePosY", 0.0)
    pos.z = config.ReadFloat("RotatePosZ", 0.0)

    axial_shift = config.ReadFloat('RotateAxialShift', 0.0)

    result, angle, axis, pos, ncopies, axial_shift = InputAngleWithPlane(
        angle, axis, pos, ncopies, axial_shift, 'Rotate')
    if not result:
        return

    if copy:
        if ncopies < 1:
            return
        config.WriteInt("RotateNumCopies", ncopies)

    config.WriteFloat("RotateAngle", angle)
    config.WriteFloat("RotateAxialShift", axial_shift)
    config.WriteFloat("RotateAxisX", axis.x)
    config.WriteFloat("RotateAxisY", axis.y)
    config.WriteFloat("RotateAxisZ", axis.z)
    config.WriteFloat("RotatePosX", pos.x)
    config.WriteFloat("RotatePosY", pos.y)
    config.WriteFloat("RotatePosZ", pos.z)

    cad.StartHistory()

    if copy:
        for i in range(0, ncopies):
            mat = geom.Matrix()
            mat.Translate(-pos)
            mat.RotateAxis(angle * 0.0174532925199433 * (i + 1), axis)
            mat.Translate(pos)
            for object in selected_items:
                new_object = object.MakeACopy()
                object.GetOwner().Add(new_object)
                cad.TransformUndoably(new_object, mat)
    else:
        mat = geom.Matrix()
        mat.Translate(-pos)
        mat.RotateAxis(angle * 0.0174532925199433, axis)
        mat.Translate(pos)
        for object in selected_items:
            cad.TransformUndoably(object, mat)

    cad.EndHistory()