diff --git a/.gitignore b/.gitignore index 022972b..c45b5b5 100644 --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,5 @@ docs/Motor.zip *.stl docs/backup/ + +Add Motor/ diff --git a/Add Motor.zip b/Add Motor.zip new file mode 100644 index 0000000..8aad504 Binary files /dev/null and b/Add Motor.zip differ diff --git a/README.md b/README.md index e44940c..24af967 100644 --- a/README.md +++ b/README.md @@ -1 +1,87 @@ -blender_Motor_Factory +# Blender Motor Factory + +This is an blender addon which can create motor. We parameterized many features of a motor and so user can generate various model in same type but different parameters. + +This addon only support [blender version 2.90.1](https://download.blender.org/release/Blender2.90/). Other version may cause unpredictable falier. + +## 1. Installation + +1. Download the project via ``git clone https://github.com/cold-soda-jay/blender_Motor_Factory.git``. +2. In Blender, go *Edit > Preference > Install* and find the file **Add Motor.zip**. Make sure it is activated. +3. Now you can find it in *Add >Mesh* + +## 2. Advanced + +### 2.1 Save model + +This Addon allow user generate various model and save the parameter as well as model as .stl file. To save the model, you can run the command in blender Console (**Shift + F4** to open it): +``bpy.ops.mesh.add_motor(save_path="Path of folder")`` + +The model will be saved as a whole entity and seperate parts + +
+ + + +### 2.2 CSV data + +The parameters of generated model will be saved into a csv file when ``save_path`` setted. Every model will be saved in a separate folder with a number as name. This number represent the Id of the model. The parameters of this model can be found in csv file. + +The position of all bolts will also be saved as a list in the file. The order of bolt position is from bottom to top. + +### 2.3 Auto generation + +To generate more models at once, you can use script ``./src/auto_generate.py``. In the script you can set the number of generated models and define several parameters when generating. Here are all parameters: + +```python + +[ +"mf_Head_Type", +"mf_Extension_Type_A", +"mf_Extension_Type_B", +"mf_Gear_Orientation_1", +"mf_Gear_Orientation_2", +"mf_Flip", +"mf_Color_Render", +"mf_Bottom_Length", +"mf_Sub_Bottom_Length", + +"mf_Lower_Gear_Dia", +"mf_Lower_Gear_Position", +"mf_Upper_Gear_Dia", + +"mf_Bit_Type", +"mf_Bolt_Orientation", +"mf_Lower_Gear_Bolt_Random", + +"mf_Lower_Gear_Bolt_Position_1", +"mf_Lower_Gear_Bolt_Position_2", + +"mf_Gear_Bolt_Random_B", +"mf_Gear_Bolt_Nummber_B", +"mf_Gear_Bolt_Position_B_1", +"mf_Gear_Bolt_Position_B_2", +"mf_Gear_Bolt_Position_B_3", + + +"mf_Upper_Bolt_Nummber", +"mf_Upper_Gear_Bolt_Random", +"mf_Upper_Gear_Bolt_Position_1", +"mf_Upper_Gear_Bolt_Position_2", +"mf_Upper_Gear_Bolt_Position_3", + +"mf_Type_B_Height_1", +"mf_Type_B_Height_2", + +"save_path", + +] +``` + +After setting the parameters, you can runthe script in command line with following command: + +``` +blender --background --python path/of/auto_generate.py" +``` + +See more details in `auto_generate.py` diff --git a/docs/blender.md b/docs/blender.md deleted file mode 100644 index bb740d2..0000000 --- a/docs/blender.md +++ /dev/null @@ -1,116 +0,0 @@ -# Motor Factory - - - -## 1. Bottom 2 - -1. The origin point should be at the bottom -2. The size of sub cylinder inner should be able to change - -## 2. Bottom 1 - -1. Only the length should be changabel - -## 3. Middle - -1. Fixed size, belong to up2 - -## 4. Up2 - -1. 4 convex Cylinder, fixed -2. Cylinder Zone - - back - - hole - - tilt - - 4 bolts cylinder - -## 5. Up1 - -1. Cylinder Zone: Amount 6+5 -2. Circle Tangent extension zone - - - - -# Questions - -1. Generate the parts using real size or relative size? -2. Are all gears of one type having same size? Are there two kind of gears? -3. How accurate should it be? Which parts are not so important for learning and which parts are very important? - - - -# Variance need to be modified - -## Bottom - -1. Length should be limited - - - -## Up part 2 - -1. **Cylinder Zone 2 (Small Gear)** - - Position: Tangent of middle line - - Radius - - $\frac{2}{3}$ -2. **Large Gear** - - Postion - - Radius: Boader at center of small gear - - $\frac{1}{3}$ -3. **Depth of both gears** - - Depends on which type -4. **Left or Right of gears** - - -## Up part 1 - -1. Thickness - -## Bolt - -> 倒角 (Use sephere) -1. Thickness -3. Radius -4. Bit Type - - Torx - - Philips - - Sloted - - Hex (Alien) - - Square -5. Bit radius -2. **Screws** - - Large Gear: 2 - - Random on up half - - Sum of angle larger than 120 - - Small Gear: 2 - - Random on bottom half - - Sum of angle larger than 120 - - Middle: 2 (fixed) - -## Extention Zone - -1. **Two types** - - Tangent of large gear - - Left or Right to the large gear - - One or two cylinders -3. **Board and details** (less important) - - - - -# 5.Okt - -1. Bolt rotation - - all same - - all random -2. Bit type -3. 4 covex empty zone (1) -4. gear up and down limit (position, dia) -5. Extension Zone - - type 1 - - type 2 -6. Flip -7. Energy part two panels - - diff --git a/docs/pic/motor-typeA.png b/docs/pic/motor-typeA.png deleted file mode 100644 index 6dba560..0000000 Binary files a/docs/pic/motor-typeA.png and /dev/null differ diff --git a/pic/parts_model.png b/pic/parts_model.png new file mode 100644 index 0000000..14d8113 Binary files /dev/null and b/pic/parts_model.png differ diff --git a/pic/saved_file.png b/pic/saved_file.png new file mode 100644 index 0000000..d63d348 Binary files /dev/null and b/pic/saved_file.png differ diff --git a/src/Motor_Factory.py b/src/Motor_Factory.py index 5bc6c73..da3ec9a 100644 --- a/src/Motor_Factory.py +++ b/src/Motor_Factory.py @@ -12,6 +12,7 @@ class Motor_Factory_Operator(bpy.types.Operator,AddObjectHelper): + #Set Genera information bl_idname = "mesh.add_motor" bl_label = "Motor Property" @@ -72,8 +73,9 @@ class Motor_Factory_Operator(bpy.types.Operator,AddObjectHelper): "save_path", ] - #Create genera types + #Create genera types and Variables + ################### General ################################## #Head Types Head_Type_List = [('mf_Head_Type_A','Type A (Two gears)','Type A'), ('mf_Head_Type_B','Type B (One gears)','Type B')] @@ -81,25 +83,9 @@ class Motor_Factory_Operator(bpy.types.Operator,AddObjectHelper): name='Type', description='Choose the type of Motor you would like', items = Head_Type_List, default = 'mf_Head_Type_B') - - #Bottom size - mf_Bottom_Length = FloatProperty(attr='mf_Bottom_Length', - name='Bottom Length', default = 6.4, - min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, - description='Length of the Bottom') - - #Bottom size - mf_Sub_Bottom_Length = FloatProperty(attr='mf_Sub_Bottom_Length', - name='Sub Bottom Length', default = 1.2, - min =0.6, soft_min = 0.1, max = 2, - description='Length of the Sub Bottom') - - - mf_Sub_Bottom_Inner_Dia = FloatProperty(attr='mf_Sub_Bottom_Inner_Dia', - name='Sub Bottom Inner Dia', default = 0.5, - min = 0, soft_min = 0, max = 0.9, - description='Length of the sub Bottom inner dia') - #Bottom Types + + #Extension zone Types + Extention_Type_List_A = [('mf_Extension_Type_1','Type 1','Type 1'), ('mf_Extension_Type_2','Type 2','Type 2'), ('mf_None','None','None') @@ -117,6 +103,8 @@ class Motor_Factory_Operator(bpy.types.Operator,AddObjectHelper): description='Choose the type of extension area you would like', items = Extention_Type_List_B, default = 'mf_Extension_Type_1') + + # Gear Orientation Orientation_List_Type_2 = [ ('mf_Ninety','90','90'), @@ -145,27 +133,28 @@ class Motor_Factory_Operator(bpy.types.Operator,AddObjectHelper): default = False, description = "Flip the gears") - - + # Set color rendering option mf_Color_Render : BoolProperty(name = "Color Render", default = False, description = "Render clor or not") - mf_Bottom_Size = FloatProperty(attr='mf_Bottom_Size', - name='Bottom Size', default = 20, - min = 0, soft_min = 0, max = 50, - description='Size of the Bottom in percent') + ################## Bottom ######################################## + #Bottom Length + mf_Bottom_Length = FloatProperty(attr='mf_Bottom_Length', + name='Bottom Length', default = 6.4, + min = 0, soft_min = 0, max = MAX_INPUT_NUMBER, + description='Length of the Bottom') - #Bit Types - Bit_Type_List = [('mf_Bit_Torx','Torx','Torx Bit Type'), - ('mf_Bit_Slot','Slot','Slot Bit Type'), - ('mf_Bit_Cross','Cross','Cross Bit Type')] - mf_Bit_Type = EnumProperty( attr='mf_Bit_Type', - name='Bit Type', - description='Choose the type of bit to you would like', - items = Bit_Type_List, default = 'mf_Bit_Torx') + #Sub Bottom length + mf_Sub_Bottom_Length = FloatProperty(attr='mf_Sub_Bottom_Length', + name='Sub Bottom Length', default = 1.2, + min =0.6, soft_min = 0.1, max = 2, + description='Length of the Sub Bottom') + + + ###################### Lower Gears for type A and B ######################################## mf_Lower_Gear_Dia = FloatProperty(attr='mf_Lower_Gear_Dia', name='Lower Gear Dia', default = 4, min = 3.5, soft_min = 0, max = 4.5, @@ -191,7 +180,7 @@ class Motor_Factory_Operator(bpy.types.Operator,AddObjectHelper): min = 310, max = 350, step=5, description='Position of bolt 2 on lower gear') - ############################################################################### + #################################### Gear option for Type B ########################################### mf_Gear_Bolt_Random_B : BoolProperty(name = "Random Bolt Position ", default = False, description = "Random Bolt Rotation") @@ -216,15 +205,24 @@ class Motor_Factory_Operator(bpy.types.Operator,AddObjectHelper): min = -60, max = 10, step=1, description='Position of bolt 2 on gear') + mf_Type_B_Height_1 = FloatProperty(attr='mf_Type_B_Height_1', + name='Hieght of Extension left', default = 7, + min = 6.3, soft_min = 0, max = 8, + description='Angle between bolts on large gear') + + + mf_Type_B_Height_2 = FloatProperty(attr='mf_Type_B_Height_2', + name='Hieght of Extension right', default =3.5, + min = 2, soft_min = 0, max = 6, + description='Angle between bolts on large gear') - ######################################################### + ########################## Upper part Type A ############################### mf_Upper_Gear_Dia = FloatProperty(attr='mf_Upper_Gear_Dia', name='Upper Gear Dia', default = 5.5, min = 5, soft_min = 0, max = 6.5, description='Diameter of upper Gear') - #Bolt on large gear mf_Upper_Bolt_Nummber = IntProperty( name='Number of Bolts', @@ -254,16 +252,8 @@ class Motor_Factory_Operator(bpy.types.Operator,AddObjectHelper): min = 0, max = 210, step=5, description='Position of bolts on large gear') - mf_Type_B_Height_1 = FloatProperty(attr='mf_Type_B_Height_1', - name='Hieght of Extension left', default = 7, - min = 6.3, soft_min = 0, max = 8, - description='Angle between bolts on large gear') - - - mf_Type_B_Height_2 = FloatProperty(attr='mf_Type_B_Height_2', - name='Hieght of Extension right', default =3.5, - min = 2, soft_min = 0, max = 6, - description='Angle between bolts on large gear') + + ###################### Bolts ############################################ bolt_orientation_list = [('mf_all_same', 'All Same','All Same'), ('mf_all_random', 'All Random', 'All Random')] @@ -272,23 +262,36 @@ class Motor_Factory_Operator(bpy.types.Operator,AddObjectHelper): description='Orientation of bolts', items = bolt_orientation_list, default = 'mf_all_same') + + #Bit Types + Bit_Type_List = [('mf_Bit_Torx','Torx','Torx Bit Type'), + ('mf_Bit_Slot','Slot','Slot Bit Type'), + ('mf_Bit_Cross','Cross','Cross Bit Type')] + mf_Bit_Type = EnumProperty( attr='mf_Bit_Type', + name='Bit Type', + description='Choose the type of bit to you would like', + items = Bit_Type_List, default = 'mf_Bit_Torx') + + ##################### Svae path ##################### save_path = StringProperty(name = "Save", default = "None", maxlen=4096, description = "Save the modell") def draw(self, context): + """ + Define the contex menu + + """ layout = self.layout col = layout.column() - #ENUMS col.label(text="General") col.prop(self, 'mf_Head_Type') if self.mf_Head_Type == "mf_Head_Type_A": col.prop(self, 'mf_Extension_Type_A') if self.mf_Extension_Type_A == 'mf_Extension_Type_1': col.prop(self, 'mf_Gear_Orientation_1') - #col.prop(self, 'mf_Flip_1') elif self.mf_Extension_Type_A == 'mf_Extension_Type_2': col.prop(self, 'mf_Gear_Orientation_2') else: @@ -341,23 +344,16 @@ def draw(self, context): elif self.mf_Head_Type == "mf_Head_Type_B": col.label(text="Bolts Position around gear") if self.mf_Extension_Type_B == "mf_None": - col.prop(self, 'mf_Gear_Bolt_Nummber_B') - - + col.prop(self, 'mf_Gear_Bolt_Nummber_B') col.prop(self, 'mf_Gear_Bolt_Random_B') if not self.mf_Gear_Bolt_Random_B: col.prop(self, 'mf_Gear_Bolt_Position_B_1') col.prop(self, 'mf_Gear_Bolt_Position_B_2') if self.mf_Extension_Type_B == "mf_None" and self.mf_Gear_Bolt_Nummber_B == 3: col.prop(self, 'mf_Gear_Bolt_Position_B_3') - - - - - - #col.prop(self, 'bf_presets') col.separator() + @classmethod def poll(cls, context): return context.scene is not None @@ -395,7 +391,13 @@ def invoke(self, context, event): return {'FINISHED'} def create_motor(self): + """Create motor + + Returns: + Motor Object + """ + # Check if the model should be svaed if self.save_path == "None": pass else: @@ -410,21 +412,24 @@ def create_motor(self): os.mkdir(path_of_folder) except: pass + # different headtype instance different object if self.mf_Head_Type == "mf_Head_Type_A": creator = mt.Type_A(self) elif self.mf_Head_Type == "mf_Head_Type_B": creator = mt.Type_B(self) + + #Create bottom part bottom = creator.create_Bottom() - #creator.save_modell(bottom.name) - - #middle = creator.create_middle() + #Create energy part (Electric socket) en_part = creator.create_en_part() - #convex = creator.create_4_convex_cyl() + #Create Upper part upper_part = creator.create_upper_part() obj_list=[upper_part,en_part] + + # Check if color should be rendered for area in bpy.context.screen.areas: # iterate through areas in current screen if area.type == 'VIEW_3D': @@ -434,13 +439,13 @@ def create_motor(self): space.shading.type = 'MATERIAL' else: space.shading.type = 'SOLID' # set the viewport shading to rendered - + + # Combine all created parts motor = creator.combine_all_obj(bottom,obj_list) motor.name = "Motor" motor.data.name = "Motor" creator.save_modell(motor) - creator.save_csv(self) - + creator.save_csv(self) return motor diff --git a/src/__init__.py b/src/__init__.py index ed61386..9503d8b 100644 --- a/src/__init__.py +++ b/src/__init__.py @@ -13,10 +13,10 @@ bl_info = { "name" : "MotorFactory", - "author" : "Joe", + "author" : "Cold-Soda-Joe", "description" : "Motor Factory", - "blender" : (2, 90, 0), - "version" : (0, 0, 1), + "blender" : (2, 90, 1), + "version" : (1, 0, 0), "location" : "View3D > Add > Mesh", "warning" : "", "category" : "Generic" @@ -25,7 +25,6 @@ import bpy from .Motor_Factory import Motor_Factory_Operator -#from .test_panel import Test_PT_Panel def add_mesh_motor_button(self, context): @@ -50,7 +49,6 @@ def register(): bpy.types.VIEW3D_MT_mesh_add.append(add_mesh_motor_button) bpy.types.VIEW3D_MT_object_context_menu.prepend(Motor_contex_menu) - #bpy.types.VIEW3D_PT_tools_objectmode.prepend(add_mesh_motor_button) #just for testing def unregister(): @@ -58,7 +56,6 @@ def unregister(): bpy.types.VIEW3D_MT_mesh_add.remove(add_mesh_motor_button) bpy.utils.unregister_class(Motor_Factory_Operator) - #bpy.types.VIEW3D_PT_tools_objectmode.remove(add_mesh_motor_button) #just for testing #if __name__ == "__main__": # register() diff --git a/src/auto_generate.py b/src/auto_generate.py new file mode 100644 index 0000000..4821a03 --- /dev/null +++ b/src/auto_generate.py @@ -0,0 +1,52 @@ +import bpy +import random + + +def generate_param(): + MotorParameters = { + "mf_Head_Type" : random.choice(["mf_Head_Type_A","mf_Head_Type_B"]), + "mf_Extension_Type_A" : random.choice(["mf_Extension_Type_1","mf_Extension_Type_2", "mf_None"]), + "mf_Extension_Type_B" : random.choice(["mf_Extension_Type_1","mf_None"]), + "mf_Gear_Orientation_1" : random.choice(['mf_zero','mf_Ninety', 'mf_HundredEighteen','mf_TwoHundredSeven']), + "mf_Gear_Orientation_2" : random.choice(['mf_Ninety', 'mf_HundredEighteen','mf_TwoHundredSeven']), + "mf_Flip" : random.choice([True,False]), + "mf_Color_Render" : False, + "mf_Bottom_Length" : random.randrange(0, 10), + "mf_Sub_Bottom_Length" : random.uniform(0.6, 2), + + "mf_Lower_Gear_Dia": random.uniform(3.5, 4.5), + "mf_Lower_Gear_Position": random.uniform( 3.6, 4.2), + "mf_Lower_Gear_Bolt_Random" : True, + + "mf_Gear_Bolt_Random_B": True, + "mf_Gear_Bolt_Nummber_B" : random.randrange(2, 3), + "mf_Type_B_Height_1" : random.uniform(6.3, 8), + "mf_Type_B_Height_2" : random.uniform(2, 6), + + "mf_Upper_Gear_Dia": random.uniform(5, 6.5), + "mf_Upper_Bolt_Nummber": random.randrange(1, 3), + "mf_Upper_Gear_Bolt_Random" : True, + + "mf_Bit_Type" : random.choice(['mf_Bit_Torx','mf_Bit_Slot','mf_Bit_Cross']), + "mf_Bolt_Orientation": "mf_all_random", + } + return MotorParameters + +def create_motor(number: int, **data): + for i in range(number): + param = generate_param() + for key, value in data.items(): + param[key] = value + motor = bpy.ops.mesh.add_motor(**param) + + + +if __name__ == "__main__": + # Change this value to set how many models should be generated + num = 5 + data = {} + # Set parameter that should be manuelly modified + data['save_path']="F:/blender_test/" # Add other param like this + create_motor(num, **data) + + diff --git a/src/motor.py b/src/motor.py index 778debb..fc191d0 100644 --- a/src/motor.py +++ b/src/motor.py @@ -388,6 +388,7 @@ def create_4_convex_cyl(self): class Type_A(Motor_Creator): param = [ + "mf_Extension_Type_A", "mf_Lower_Gear_Dia", "mf_Lower_Gear_Position", "mf_Upper_Gear_Dia", @@ -435,10 +436,13 @@ def init_modify(self,factory): if self.ex_type == 'mf_Extension_Type_1': self.gear_orientation = factory.mf_Gear_Orientation_1 + self.param.append("mf_Gear_Orientation_1") elif self.ex_type == 'mf_Extension_Type_2': self.gear_orientation = factory.mf_Gear_Orientation_2 + self.param.append("mf_Gear_Orientation_2") else: self.gear_orientation = factory.mf_Gear_Orientation_1 + self.param.append("mf_Gear_Orientation_2") self.upper_gear_dia = factory.mf_Upper_Gear_Dia @@ -465,8 +469,15 @@ def init_modify(self,factory): self.param.append("mf_Upper_Gear_Bolt_Position_3") - - self.motor_param += self.param + self.motor_param = self.param + [ + "mf_Head_Type", + "mf_Flip", + "mf_Color_Render", + "mf_Bottom_Length", + "mf_Sub_Bottom_Length", + "mf_Bit_Type", + "mf_Bolt_Orientation", + ] self.l_bolt_list = [] self.s_bolt_list = [] @@ -1200,7 +1211,15 @@ def init_modify(self,factory): self.type_B_Height_1 = factory.mf_Type_B_Height_1 self.type_B_Height_2 = factory.mf_Type_B_Height_2 - self.motor_param += self.param + self.motor_param = self.param + [ + "mf_Head_Type", + "mf_Flip", + "mf_Color_Render", + "mf_Bottom_Length", + "mf_Sub_Bottom_Length", + "mf_Bit_Type", + "mf_Bolt_Orientation", + ] #self.l_bolt_list = [] #self.s_bolt_list = [] diff --git a/src/utility.py b/src/utility.py index 21276b2..b557d8c 100644 --- a/src/utility.py +++ b/src/utility.py @@ -11,6 +11,14 @@ class Factory: + """Basic Class for creating motor. Contains several basic methods and variables. + + + To use this the defined motor operator should be created and given when initiationg: + + e.g.: creator = Factory(operator) + """ + ####################################################################################################################### ##################### Constants ####################################################################################### @@ -27,9 +35,12 @@ class Factory: BOLT_THREAD_LENGTH = 1.4 BOLT_THREAD_DIA = 0.2 + # Board BOARD_THICKNESS = 0.1 FOUR_CYL_DIA = 0.7 + # 4 convex part + C1_LENGTH = 0 C2_LENGTH = 0 C3_LENGTH = 0 @@ -75,18 +86,8 @@ class Factory: color_render = False gear_Flip = False - #Save path + #Define the parameter that should be svaed in csv file motor_param = [ - "mf_Head_Type", - "mf_Extension_Type", - "mf_Gear_Orientation", - "mf_Flip", - "mf_Color_Render", - "mf_Bottom_Length", - "mf_Sub_Bottom_Length", - - "mf_Bit_Type", - "mf_Bolt_Orientation", ] key_list = [] @@ -98,6 +99,12 @@ class Factory: out_bolt_position = [] def __init__(self,factory): + """initiate variables. + + Args: + factory ([bpy.types.Operator]): [Operator] + """ + self.head_Type = factory.mf_Head_Type self.init_x = factory.init_x self.init_y = factory.init_y @@ -119,21 +126,43 @@ def __init__(self,factory): self.color_render = factory.mf_Color_Render - + self.motor_param += [ + "mf_Head_Type", + "mf_Flip", + "mf_Color_Render", + "mf_Bottom_Length", + "mf_Sub_Bottom_Length", + "mf_Bit_Type", + "mf_Bolt_Orientation", + + ] self.save_path = factory.save_path self.id_Nr = factory.id_Nr self.init_modify(factory) def init_modify(self,factory): + """Init other variables by demand + + Args: + factory (bpy.types.Operator): [Operator] + """ pass ############################################################################################################################## - ########################## Utility ########################################################################################### + ########################## Genera Utility #################################################################################### def combine_all_obj(self, main_obj, object_list): + """Combine objects. Joint all opjects in object_list into main_obj + + Args: + main_obj ([bpy.types.Object]): [main object] + object_list ([list]): [List of objects that shold be joined into main object] + + Returns: + [bpy.types.Object]: [Combined object. Should have same attribute as main_obj] + """ bpy.ops.object.select_all(action='DESELECT') - #bpy.ops.object.mode_set(mode='OBJECT') bpy.context.view_layer.objects.active = main_obj for obj in object_list: try: @@ -149,6 +178,16 @@ def combine_all_obj(self, main_obj, object_list): return main_obj def rotate_around_point(self, origin, Angle, obj_position): + """Caculate rotation for 2D case. + + Args: + origin (tuple): Original point which object should rotate around it. Size: 1*2 + Angle (float): Rotate angle + obj_position (tuple): Object position. Size: 1*2 + + Returns: + tuple: Rotated object position + """ if type(Angle) == int or float: rot = radians(Angle) else: @@ -159,6 +198,17 @@ def rotate_around_point(self, origin, Angle, obj_position): return x+origin[0],y+origin[1] def create_ring(self, position,height,radius,thickness): + """Create ring object + + Args: + position (tuple): position of ring. Size: 1*3 + height (float): height of ring + radius (float): raius of ring + thickness (float): Thickness of ring + + Returns: + bpy.type.Object: Created ring + """ bpy.ops.mesh.primitive_cylinder_add(radius=radius, depth=height, location=position) cly_out = bpy.context.object bpy.ops.mesh.primitive_cylinder_add(radius=radius-thickness, depth=height+1, location=position) @@ -169,15 +219,27 @@ def create_ring(self, position,height,radius,thickness): bool_in.object = cly_in bpy.context.view_layer.objects.active = cly_out res = bpy.ops.object.modifier_apply(modifier='bool_in') + # Delete the cylinder.x cly_in.select_set(True) bpy.ops.object.delete() - #if rotation is not None: - # bpy.context.view_layer.objects.active = cly_out - # bpy.ops.transform.rotate(value=rotation[0],orient_axis=rotation[1]) + return cly_out - def add_mesh(self, name, verts, faces, edges=None, col_name="Collection"): + def add_mesh(self, name, verts, faces, edges=None, col_name="Collection"): + """Create mesh using verts and faces + + Args: + name (str): + verts (tuple): List of verts + faces (tuple): List of faces + edges (Tuple, optional): [description]. Defaults to None. + col_name (str, optional): [description]. Defaults to "Collection". + + Returns: + [bpy.type.objects]: + """ + if edges is None: edges = [] mesh = bpy.data.meshes.new(name) @@ -189,6 +251,16 @@ def add_mesh(self, name, verts, faces, edges=None, col_name="Collection"): return obj def add_torx(self,position,size,depth): + """Create torx model + + Args: + position (tuple): + size (float): [description] + depth (float): [description] + + Returns: + bpy.type.Object: Torx object + """ x = position[0] y = position[1] z = position[2] + 0.2 @@ -245,6 +317,13 @@ def add_torx(self,position,size,depth): return obj def diff_obj(self, main, slave): + """Boolean oeration for two object. + + Args: + main (bpy.type.objects): Main object that should be cutted + slave (bpy.type.objects): Slave object that cuts main object + + """ boolean = main.modifiers.new('bool_in', 'BOOLEAN') boolean.operation = 'DIFFERENCE' boolean.object = slave @@ -254,6 +333,17 @@ def diff_obj(self, main, slave): return res def add_vector(self,v1,v2,minus=0,height=0): + """Add each element in two vectors + + Args: + v1 (list): [description] + v2 (list): [description] + minus (int, optional): Set to 1, then v1 - v2. Set to 0, then v1 + v2. Defaults to 0. + height (int, optional): Set to 1, add height. Defaults to 0. + + Returns: + list: result vector + """ out = [] for i in range(len(v1)): if minus == 1: @@ -265,6 +355,15 @@ def add_vector(self,v1,v2,minus=0,height=0): return out def create_motor_main(self, position, height, width, length): + """Create motor botom main part(a cutted cylinder) + + Args: + position ([type]): [description] + height ([type]): [description] + width ([type]): [description] + length ([type]): [description] + + """ # Add main cylinder cylinder_r = width/2 @@ -325,6 +424,7 @@ def create_bolt(self, position,rotation=None,only_body=False): bit_type = self.bit_type orientation = self.bolt_ortientation out_dia = self.BOLT_RAD + # Check if only body should be created if only_body : out_length = 0.3 z_in = position[2] + out_length/2 - 0.15 @@ -359,8 +459,7 @@ def create_bolt(self, position,rotation=None,only_body=False): #Create Shell for Bolt out_cyl = self.create_ring(position, out_length, out_dia, 0.2) - #bpy.ops.mesh.primitive_cylinder_add(radius=out_dia, depth=out_length, location=position) - #out_cyl = bpy.context.object + out_cyl.name = 'out_cylinder' bpy.ops.mesh.primitive_uv_sphere_add(radius=in_dia, location=(position[0],position[1],z_sphe)) @@ -375,11 +474,12 @@ def create_bolt(self, position,rotation=None,only_body=False): bool_in.operation = 'DIFFERENCE' bool_in.object = cut_cyl bpy.context.view_layer.objects.active = sphere - res = bpy.ops.object.modifier_apply(modifier='bool_in') - # Delete the cylinder.x + res = bpy.ops.object.modifier_apply(modifier='bool_in') + # Delete the cylinder cut_cyl.select_set(True) bpy.ops.object.delete() + #Create bit of bolts if bit_type == 'mf_Bit_Slot': bpy.ops.mesh.primitive_cube_add(location=(position[0],position[1],z_sphe+ in_dia/3)) bpy.ops.transform.resize(value=(in_dia*1.5, 0.05, 0.2)) @@ -460,7 +560,7 @@ def create_bolt(self, position,rotation=None,only_body=False): bit.select_set(True) bpy.ops.object.delete() - + # rend color if self.color_render: self.rend_color(out_cyl,"Plastic") self.rend_color(sphere,"Bit") @@ -469,10 +569,8 @@ def create_bolt(self, position,rotation=None,only_body=False): bolt = self.combine_all_obj(thread,[sphere,in_cyl]) bolt.name = 'Bolt_'+str(self.bolt_num) self.bolt_num+=1 - #self.save_modell(bolt) - #part = self.combine_all_obj(out_cyl,[bolt]) - + # rotate the bit if orientation == 'mf_all_random': Angle = random.randrange(0, 360, 10) bpy.ops.object.select_all(action='DESELECT') @@ -487,6 +585,12 @@ def create_bolt(self, position,rotation=None,only_body=False): return [out_cyl,bolt] def rend_color(self, obj, part): + """Rend color option. + + Args: + obj (bpy.type.Objects): Object to be colored + part (str): Keyword for color rendering + """ mat = bpy.data.materials.new(name="Material") @@ -521,6 +625,11 @@ def rend_color(self, obj, part): bpy.context.view_layer.objects.active = None def rotate_object(self, object_rotate): + """Rotate object after creation. Rotation will set by user + + Args: + object_rotate (bpy.type.Objects): Object to be rotated + """ rotation, length_relativ, mirror = self.orient_dict[self.gear_orientation] x,y,z = object_rotate.location bpy.ops.object.select_all(action='DESELECT') @@ -545,6 +654,11 @@ def rotate_object(self, object_rotate): pass def init_key_list(self,factory): + """Initiate key list for saving to csv + + Args: + factory (bpy.types.Operator): Operator + """ key_list = ["Nr."] for name in dir(factory): if name[0:3] == "mf_": @@ -553,12 +667,25 @@ def init_key_list(self,factory): self.key_list=key_list def init_csv(self,path, factory): + """initiate csv file + + Args: + path (str): + factory (bpy.types.Operator): + """ self.init_key_list(factory) with open(path, "a+", encoding='utf-8') as log: writer = csv.writer(log) writer.writerow(self.key_list) def write_data(self, path, data, factory): + """Write data into csv + + Args: + path (str): + data (dict): + factory (bpy.types.Operator): + """ csvdict = csv.DictReader(open(path, 'rt', encoding='utf-8', newline='')) dictrow = [row for row in csvdict if len(row) > 0 ] @@ -571,6 +698,11 @@ def write_data(self, path, data, factory): wrier.writerow(wowow) def save_csv(self, factory): + """Save csv file + + Args: + factory (bpy.types.Operator): + """ if self.save_path == "None": pass else: @@ -583,6 +715,14 @@ def save_csv(self, factory): self.write_data(csv_path,data, factory) def create_data_list(self, factory): + """Create data list ` + + Args: + factory (bpy.types.Operator): + + Returns: + dict: Dictionary of parameter + """ data_list=[str(self.id_Nr)] for name in dir(factory): @@ -596,7 +736,12 @@ def create_data_list(self, factory): return data def save_modell(self,modell, addtional = None): - + """Save model + + Args: + modell (bpy.types.Objects): + addtional (bpy.types.Objects, optional): If other model should be saved in the same file. Defaults to None. + """ if self.save_path == "None": pass else: @@ -618,6 +763,11 @@ def save_modell(self,modell, addtional = None): bpy.ops.object.select_all(action='DESELECT') def calculate_bolt_position(self,root_position): + """Caculate bolts positions + + Args: + root_position (list): Bolt position before rotation + """ x ,y, z = root_position position=[] rotation, length_relativ, mirror = self.orient_dict[self.gear_orientation]