• Login
sketchucation logo sketchucation
  • Login
πŸ€‘ SketchPlus 1.3 | 44 Tools for $15 until June 20th Buy Now

How do you make individual components

Scheduled Pinned Locked Moved Plugins
12 Posts 5 Posters 1.4k Views 5 Watching
Loading More Posts
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • B Offline
    Brendon5374
    last edited by 22 Apr 2010, 08:49

    Here is something I have edited for myself from cab.rb from the ruby libray. I end up with panels, a complete cabinet, etc. But when I point the cursor at the object in sketchup, there are no individual components. No individual pieces of timber I can point to, move around., resize, etc. How do I make this script come up with a left panel that is a component and not part of the whole entity.

    When I use the menu without the plugin I draw the dimensions, push/pull, select all, and "make component". Then I do the same over again. I get what I want then. How can I get the same result doing a plugin script?

    I don't know the ettiquette here, so sorry if pasting all this is wrong. But here goes:

    require 'sketchup.rb'
    #-----------------------------------------------------------------------------
    def create_cab

    prompts = ["Cabinet Width", "Cabinet Height", "Cabinet Depth","With Kick?"]
    values = [100.cm, 100.cm, 60.cm , 10.cm ]
    thick = 1.6.cm  #<----panel thickness
    results = inputbox prompts, values, "Cabinet Dimensions"
    width, height, depth, kick = results
    if (kick <= 0.0.cm)
       then kick = 0.01.cm
    end
    

    #-----------------------------------------------------------------------------
    model = Sketchup.active_model
    model.start_operation "Create Cab"
    entities = model.active_entities
    group = entities.add_group
    entities = group.entities

    ls=[]   #left panel
    ls[0] = [0, depth, kick]
    ls[1] = [0, depth, height-thick]
    ls[2] = [0, thick, height-thick]
    ls[3] = [0, thick, kick]
    ls_base = entities.add_face ls
    ls_base.pushpull thick
    
    
    
    x = width-thick
    rs=[]   #right panel
    rs[0] = [x, depth, kick]
    rs[1] = [x, depth, height-thick]
    rs[2] = [x, thick, height-thick]
    rs[3] = [x, thick, kick]
    rs_base = entities.add_face rs
    rs_base.pushpull thick
    
    
    
    
    rp=[]   #rear panel
    rp[0] = [0, depth, kick]
    rp[1] = [0, depth+thick, kick]
    rp[2] = [0, depth+thick, height-thick]
    rp[3] = [0, depth, height-thick]
    rp_base = entities.add_face rp
    rp_base.pushpull -width
    
    top=[]   #top 
    top[0] = [thick, 10.cm, height-thick]
    top[1] = [thick, 0+thick, height-thick]
    top[2] = [thick, 0+thick, height-thick-thick]
    top[3] = [thick, 10.cm, height-thick-thick]
    top_base = entities.add_face top
    top_base.pushpull width-thick-thick
    
    
    
    top=[]   #top 
    top[0] = [thick, depth-10.cm, height-thick]
    top[1] = [thick, depth, height-thick]
    top[2] = [thick, depth, height-thick-thick]
    top[3] = [thick, depth-10.cm, height-thick-thick]
    top_base = entities.add_face top
    top_base.pushpull width-thick-thick
    
    
    
    btm=[]   #bottom shelf
    btm[0] = [thick, thick, kick+thick]
    btm[1] = [thick, depth, kick+thick]
    btm[2] = [thick, depth, kick+0]
    btm[3] = [thick, thick, kick+0]
    btm_base = entities.add_face btm
    btm_base.pushpull width-thick-thick
    
    
    
    
    
    kickf=[]   #kicktoe panel front
    kickf[0] = [0, 4.cm, 0]
    kickf[1] = [0, 4.cm+thick, 0]
    kickf[2] = [0, 4.cm+thick, kick]
    kickf[3] = [0, 4.cm, kick]
    kickf_base = entities.add_face kickf 
    kickf_base.pushpull -width
    
    
    kickb=[]   #kicktoe panel back
    kickb[0] = [0, depth-4.cm, 0]
    kickb[1] = [0, depth-4.cm-thick, 0]
    kickb[2] = [0, depth-4.cm-thick, kick]
    kickb[3] = [0, depth-4.cm, kick]
    kickb_base = entities.add_face kickb 
    kickb_base.pushpull -width
    

    #-----------------------------------------------------------------------------
    view = model.active_view
    view.zoom_extents
    #-----------------------------------------------------------------------------
    prompts = ["Door Height", "Top Rail Width", "Bottom Rail Width", "Stile Width" ]
    values = [100.cm , 10.cm , 10.cm , 3.3.cm ]
    results = inputbox prompts, values, "Door Frame Dimensions"
    height, top, btm, sw = results
    #----------------------------------Do Left Door
    ld=[] #left style, left door
    ld[0] = [0, 0, kick]
    ld[1] = [0, 0, height]
    ld[2] = [0, thick, height]
    ld[3] = [0, thick, kick]
    ld_base = entities.add_face ld
    ld_base.pushpull -sw

    x = width/2-sw
    ld=[]    #right style, left door
    ld[0] = [x, 0, kick]
    ld[1] = [x, 0, height]
    ld[2] = [x, thick, height]
    ld[3] = [x, thick, kick]
    ld_base = entities.add_face ld 
    ld_base.pushpull -sw
    
    x = sw
    ld=[]    #top rail, left door
    ld[0] = [x, 0, height-top]
    ld[1] = [x, thick,height-top]
    ld[2] = [x, thick, height]
    ld[3] = [x, 0, height]
    ld_base = entities.add_face ld
    ld_base.pushpull width/2-sw-sw
    
    x = sw
    ld=[]    #btm rail, left door
    ld[0] = [x, 0, kick]
    ld[1] = [x, 0, kick+btm]
    ld[2] = [x, thick, kick+btm]
    ld[3] = [x, thick, kick]
    ld_base = entities.add_face ld 
    ld_base.pushpull width/2-sw-sw
    
    x = sw
    ld=[]    #glazing panel, left door
    ld[0] = [x, thick/2, height-top]
    ld[1] = [x, thick, height-top]
    ld[2] = [x, thick, kick+btm]
    ld[3] = [x, thick/2, kick+btm]
    ld_base = entities.add_face ld 
    ld_base.material = Sketchup::Color.new (236,201, 101)
    ld_base.material.alpha = 0.7 
    ld_base.pushpull width/2-sw-sw
    

    #----------------------------------- Do Right Door
    x = width/2+sw
    ld=[] #left style, right door
    ld[0] = [x, 0, kick]
    ld[1] = [x, 0, height]
    ld[2] = [x, thick, height]
    ld[3] = [x, thick, kick]
    ld_base = entities.add_face ld
    ld_base.pushpull sw

    x = width-sw
    ld=[]    #right style, right door
    ld[0] = [x, 0, kick]
    ld[1] = [x, 0, height]
    ld[2] = [x, thick, height]
    ld[3] = [x, thick, kick]
    ld_base = entities.add_face ld 
    ld_base.pushpull -sw
    
    x = width-sw
    ld=[]    #top rail, right door
    ld[0] = [x, 0, height-top]
    ld[1] = [x, thick,height-top]
    ld[2] = [x, thick, height]
    ld[3] = [x, 0, height]
    ld_base = entities.add_face ld
    ld_base.pushpull width/2-sw-sw
    
    x = width-sw
    ld=[]    #btm rail, right door
    ld[0] = [x, 0, kick]
    ld[1] = [x, 0, kick+btm]
    ld[2] = [x, thick, kick+btm]
    ld[3] = [x, thick, kick]
    ld_base = entities.add_face ld 
    ld_base.pushpull width/2-sw-sw
    
    x = width-sw
    ld=[]    #glazing panel, right door
    ld[0] = [x, thick/2, height-top]
    ld[1] = [x, thick, height-top]
    ld[2] = [x, thick, kick+btm]
    ld[3] = [x, thick/2, kick+btm]
    ld_base = entities.add_face ld 
    ld_base.material = Sketchup::Color.new (236,201, 101)
    ld_base.material.alpha = 0.7 
    ld_base.pushpull width/2-sw-sw
    

    #-----------------------------------------------------------------------------
    prompts = ["Counter Top Height", "Thickness", "Reveal"]
    values = [100.cm , 3.3.cm , 1.cm ]
    results = inputbox prompts, values, "Countertop Optional"
    height, th, reveal = results

    top=[]   #countertop 
    top[0] = [0, thick, height]
    top[1] = [0, thick, height+reveal]
    top[2] = [0, 0, height+reveal]
    top[3] = [0, 0, height+th]
    top[4] = [0, depth, height+th]
    top[5] = [0, depth, height]
    top_base = entities.add_face top
    top_base.pushpull -width
    

    #-----------------------------------------------------------------------------
    model.commit_operation
    end
    #-----------------------------------------------------------------------------
    if( not file_loaded?("Cab.rb") )
    add_separator_to_menu("Plugins")
    UI.menu("Plugins").add_item("Cab") { create_cab }
    end
    #-----------------------------------------------------------------------------
    file_loaded("cab.rb")

    1 Reply Last reply Reply Quote 0
    • thomthomT Offline
      thomthom
      last edited by 22 Apr 2010, 09:58

      I'm having a quick look at it.

      However, when posting code, please wrap it in Code tags to the formatting is preserved. And when posting whole scripts like this you might as well just post the .rb file itself.

      Thomas Thomassen β€” SketchUp Monkey & Coding addict
      List of my plugins and link to the CookieWare fund

      1 Reply Last reply Reply Quote 0
      • thomthomT Offline
        thomthom
        last edited by 22 Apr 2010, 10:03

        I see.

        The reason you're not getting any components are because you are not creating any.

        You must explicitly create a group or component and add the entities to it.
        You are doing it once in the script:
        group = entities.add_group
        http://code.google.com/apis/sketchup/docs/ourdoc/entities.html#add_group

        Here you are creating a group. You must do this for each object you want and add the entities to that group.

        Thomas Thomassen β€” SketchUp Monkey & Coding addict
        List of my plugins and link to the CookieWare fund

        1 Reply Last reply Reply Quote 0
        • Dave RD Offline
          Dave R
          last edited by 22 Apr 2010, 10:38

          I looked at the link Thomas but I didn't see the answer. If you want to make a component instead of a group, would you replace

          group = entities.add_group
          

          with

          component = entities.add_component
          

          ?

          Etaoin Shrdlu

          %

          (THERE'S NO PLACE LIKE)

          G28 X0.0 Y0.0 Z0.0

          M30

          %

          1 Reply Last reply Reply Quote 0
          • thomthomT Offline
            thomthom
            last edited by 22 Apr 2010, 11:12

            To to create a component you first need to create a component definition and add the entities to it. Then place instances of that definitions entities.add_instance.

            I deliberately just explained groups as they are more straight forward. So that Brendon could see the concept of creating isolated geometry via Ruby.

            Thomas Thomassen β€” SketchUp Monkey & Coding addict
            List of my plugins and link to the CookieWare fund

            1 Reply Last reply Reply Quote 0
            • Dave RD Offline
              Dave R
              last edited by 22 Apr 2010, 12:10

              Thanks Thomas.

              I was just asking because I downloaded Dan's revision of box.rb and was wondering about changing it to make components instead of groups. I was thinking that it might be a tool to speed up some of my drawing processes but in thinking about it, I decided it will just replace one operation with another.

              Thanks again.

              Etaoin Shrdlu

              %

              (THERE'S NO PLACE LIKE)

              G28 X0.0 Y0.0 Z0.0

              M30

              %

              1 Reply Last reply Reply Quote 0
              • B Offline
                Brendon5374
                last edited by 22 Apr 2010, 13:36

                Thank you Thomas and Dave for your replies. I was pretty sure there had to be more script for each piece (object). I'm not too familar with the syntax. And reading all this is daunting for me. Basically, I was just cannabalizing open files to suit my purpose; and beyond what I understood from doing that, I'm a bit lost when off the beaten track. I read the links you gave, and I tried, but came up lacking.

                I do not know what to put with say,

                ls=[] #left panel
                ls[0] = [0, depth, kick]
                ls[1] = [0, depth, height-thick]
                ls[2] = [0, thick, height-thick]
                ls[3] = [0, thick, kick]
                ls_base = entities.add_face ls
                ls_base.pushpull thick

                to turn it into a component. I pasted every line you gave, this way and that- front and back. But I couldn't figure it. Monkey see-monkey do, has it limits. ha ha.

                1 Reply Last reply Reply Quote 0
                • D Offline
                  Doi
                  last edited by 29 Apr 2010, 03:46

                  Hi,

                  My first post, so before anything else, hello πŸ˜„

                  A bit of background on my component issue...
                  I have a model that I have 'inherited' (approximately 130 buildings) that need to be cleaned up - basically lots of unconnected entities, and components with materials applied to the back face etc. I have thrown together a quick and dirty script to fix these issues (I was a little surprised at how easy it was to fix all that; ruby is very nice to use) πŸ˜‰
                  Where things have gone a little screwy, is when I try to re-create the individual components.

                  All my searching keeps pointing me back to the API documentation, which is fine, but I must not be interpreting it correctly, and am now just going round in circles?..

                  The basic process I am trying to do is:

                  temp_group = exploded_entities.add_group
                  adjusted_component = temp_group.to_component
                  

                  The API docs state that calling the explode method on a ComponentInstancewill return an Entitiesobject. I read this as an Entities container (array?) filled with the individual Entityobjects that make up the building - the Entities container class is the only one with the add_group method!?
                  Functionally I am able to access the exploded building as expected, as I said above the clean up steps work no worries, what I am finding is that the exploded_entities object is of type Array and as such throws a no method error when calling add_group?

                  Here is the code in question:

                  # output working component
                  puts e.typename + "; " + compname
                  if exploded_component = e.explode
                    puts "Exploded into; " + exploded_component.class.to_s
                    # parse component entities
                    exploded_component.each do |ce|
                      ...fixing stuff here
                    end #end do
                  	
                  #re-create component
                  temp_group =  exploded_component.add_group
                  adj_component = temp_group.to_component
                  				
                  puts "Recreated; " + adj_component.name
                  puts "Total Faces; " + totalfaces.to_s + ";;Adjusted; " + adjusted.to_s
                  

                  Here is the console output:
                  console.PNG

                  I know it'll be something really simple - it usually is πŸ˜•

                  Thanks in advance

                  1 Reply Last reply Reply Quote 0
                  • TIGT Offline
                    TIG Moderator
                    last edited by 29 Apr 2010, 11:52

                    When you explode a ComponentInstance it returns an Array of Entities NOT an 'Entities' object.
                    There are several ways to get available 'entities'
                    Sketchup.active_model.entities

                    ALL model's entities

                    Sketchup.active_model.active_entities

                    accessible entities in this 'edit' session - if not edit it is == previous example

                    definition.entites

                    the entities in the definition

                    group.entities

                    the entities in the group.

                    The add_... methods apply to Entities.
                    So to add a group to the model use
                    new_group=Sketchup.active_model.entities.add_group()
                    then get that group's entities and add to them
                    new_group.entities.add_cpoint([1,2,3])

                    So in your case let's assume the grouped building is done something like this...

                    
                    ### we have already somehow got an array of the required 'bits'...
                    group=Sketchup.active_model.entities.add_group(an_array_of_entities)
                    ### this method can lead to Bugsplats BUT with the recent SUp MR it seems more stable
                    ### now you have group in the model that holds the 'bits'...
                    inst=group.to_component
                    defn=inst.definition
                    defn.name="defn_name"
                    defn.decription="defn_desc"
                    ### you could then  erase the 'inst' and reinsert an new one if needed, or just transform! it to anew location etc...
                    
                    

                    πŸ€“

                    TIG

                    1 Reply Last reply Reply Quote 0
                    • D Offline
                      Doi
                      last edited by 30 Apr 2010, 01:45

                      Hi TIG,

                      thanks for the clarification, it is nice to know I wasn't completely lost and was heading down the right track in one of my circular attempts - when I encountered an "All entities must have a common parent" error I went back to my initial attempt for my first post... πŸ˜‰

                      The current issue now seems to be that my exploded_entities need a reference to their 'parent' before being added to the group, yet I thought this is what add_group/to_component process was doing? From what I understand from the API, you must have a Component Instance first, then use it to create the Component Definition - then multiple Instances can be created under the Definition?

                      Using your example, my code becomes:

                      orig_entities = Sketchup.active_model.entities
                      ### Note; there is (correctly) no difference between calling .entities, or .active_entities here
                      ...
                      #re-create component
                      temp_group =  orig_entities.add_group(exploded_component)
                      adj_component = temp_group.to_component
                      adj_definition = adj_component
                      adj_definition.name= orig_definition.name
                      adj_definition.description= orig_definition.description
                      

                      The console throws:
                      Console02.PNG

                      Line 42 is the temp_group = orig_entities.add_group(exploded_component) method call.

                      If it helps, here is the entire script:

                      require 'sketchup.rb'
                      
                      #
                      #
                      #
                      def parsecomponents
                      	# containers
                      	adjustedcomps = Sketchup;;Entities.new
                      	# data
                      	model = Sketchup.active_model
                      	orig_entities = model.entities
                      	
                      	layers = model.layers
                      	unattached_layer = layers.add "Unattached Elements" #anything that ends up here to be deleted...
                      	
                      	puts "Starting-----------------------------"
                      	orig_entities.each do |e|
                      		case e
                      			when Sketchup;;ComponentInstance
                      				totalfaces = 0
                      				adjusted = 0
                      				orig_definition = e.definition
                      				orig_transform = e.transformation
                      				# output working component
                      				puts e.typename + "; " + orig_definition.name
                      				if exploded_component = e.explode
                      					puts "Exploded into; " + exploded_component.class.to_s
                      					# parse component entities
                      					exploded_component.each do |ce|
                      						# swap material if required
                      						if ce.is_a? Sketchup;;Face
                      							totalfaces += 1
                      							if !ce.material && ce.back_material
                      								ce.material= ce.back_material
                      								ce.back_material= nil
                      								adjusted += 1
                      							end #end if
                      						end #end if
                      					end #end do	
                      					
                      					#re-create component
                      					temp_group =  Sketchup.active_model.entities.add_group(exploded_component)
                      					adj_component = temp_group.to_component
                      					adj_definition = adj_component
                      					adj_definition.name= orig_definition.name
                      					adj_definition.description= orig_definition.description
                      						
                      					puts "Recreated; " + adj_definition.name
                      					puts "Total Faces; " + totalfaces.to_s + ";;Adjusted; " + adjusted.to_s
                      				else
                      					UI.messagebox "Failed to Explode Component!"
                      				end
                      			else 
                      				# anything other than a component is not wanted...
                      				e.layer= unattached_layer
                      				puts e.typename + " moved to Unattached Layer!"
                      			end # end case
                      	end # end do
                      	puts
                      	puts "Completed----------------------"
                      end # end parsecomponents
                      
                      ###########################################
                      if(file_loaded("swapmaterials02.rb"))
                      	menu = UI.menu("Plugins");
                      	menu.add_item("Parse Model") {parsecomponents}
                      end
                      #------------------------------------------
                      
                      file_loaded("swapmaterials02.rb")
                      

                      Cheers Doi! πŸ’š

                      1 Reply Last reply Reply Quote 0
                      • TIGT Offline
                        TIG Moderator
                        last edited by 30 Apr 2010, 09:43

                        Try this...

                            require 'sketchup.rb'
                        
                            #
                            #
                            #
                            def parsecomponents
                               # containers
                               ###adjustedcomps = Sketchup;;Entities.new ###NOT USED LATER ???
                               # data
                               model = Sketchup.active_model
                               # model.start_operation("parsecomponents") ### SEE BELOW...***
                               orig_entities = model.entities
                               
                               layers = model.layers ###???
                               unattached_layer = layers.add "Unattached Elements" #anything that ends up here to be deleted... ???
                               
                               puts "Starting-----------------------------"
                               orig_entities.to_a.each do |e| ### NOTE HOW I MADE IT AN array FOR SAFETY
                                    if e.class == Sketchup;;ComponentInstance ### PROBABLY EASIER THAN class ???
                                        totalfaces = 0
                                        adjusted = 0
                                        orig_definition = e.definition
                                        orig_transform = e.transformation
                                        # output working component
                                        puts e.typename + "; " + orig_definition.name
                                        if exploded_component = e.explode ### THIS IS AN array
                                           puts "Exploded into; " + exploded_component.class.to_s
                                           # parse component entities
                                           exploded_component.each do |ce|
                                              # swap material if required
                                              if ce.is_a? Sketchup;;Face
                                                 totalfaces += 1
                                                 if !ce.material && ce.back_material
                                                    ce.material= ce.back_material
                                                    ce.back_material= nil
                                                    adjusted += 1
                                                 end #end if
                                              end #end if
                                           end #end do   
                                           #re-create component
                                           temp_group =  orig_entities.add_group(exploded_component) ### ADD it were it was
                                           adj_component = temp_group.to_component
                                           adj_definition = adj_component.definition ##### POINT TO THE DEFN !!!!!
                                           # name=orig_definition.name ### USED below***
                                           adj_definition.name= orig_definition.name ##### THIS will add [1] to the end as the original exists
                                           adj_definition.description= orig_definition.description   
                                           puts "Recreated; " + adj_definition.name
                                           puts "Total Faces; " + totalfaces.to_s + ";;Adjusted; " + adjusted.to_s
                                           ### YOU COULD remove the original definition too...
                                           ### neeeds start/commit ### ***
                                           # orig_definition.name = orig_definition.name+rand.to_s ### rename temporarily
                                           # orig_definition.entities.erase_entites(orig_definition.entities)
                                           # adj_definition.name = name
                                           ### the orig_defn is now emppty and will go from the browser after the 'commit' ***
                                           ### the new definition has it's name
                                        else
                                           UI.messagebox "Failed to Explode Component!"
                                        end
                                     else # anything other than a component is not wanted...
                                        e.layer= unattached_layer
                                        puts e.typename + " moved to Unattached Layer!"
                                        ### alternatively ADD erase! HERE AND AVOID layer COMPLICATIONS
                                        # e.erase! if e.valid?
                                        # puts e.to_s+" ERASED."
                                        ### valid? traps if you delete an edge that had aface that's then not available to erase next!
                                     end # end IF ###
                               end # end do
                               puts
                               puts "Completed----------------------"
                               # model.commit_operation ###***
                            end # end parsecomponents
                        
                            ###########################################
                            if(file_loaded("swapmaterials02.rb"))
                               menu = UI.menu("Plugins");
                               menu.add_item("Parse Model") {parsecomponents}
                            end
                            #------------------------------------------
                        
                            file_loaded("swapmaterials02.rb")
                        

                        BUT to be honest I think you are making it overly complicated, as you can edit the definition's contents directly thus

                        require 'sketchup.rb'
                        def parsecomponents
                          model = Sketchup.active_model
                          model.start_operation("parsecomponents",true)
                          ### makes it undobale
                          ents = model.entities
                          puts "Starting-----------------------------"
                          ents.to_a.each{|e|
                            if e.class == Sketchup;;ComponentInstance
                              totalfaces = 0
                              adjusted = 0
                              defn = e.definition
                              begin
                                defn.entities.each{|e|
                                  if e.class==Sketchup;;Face
                                    totalfaces += 1
                                    if !e.material && e.back_material
                                      e.material= e.back_material
                                      e.back_material= nil
                                      adjusted += 1
                                    end #end if
                                  end #end if
                                }
                              rescue
                                UI.messagebox "Failed to Edit Component!"
                              end#begin
                            else # anything other than a component is not wanted...
                              e.erase! if e.valid?
                              puts e.to_s+" ERASED."
                            end # end IF ###
                          }
                          puts "Recreated; " + defn.name
                          puts "Total Faces; " + totalfaces.to_s + "; Adjusted; " + adjusted.to_s
                          puts "Completed----------------------"
                          model.commit_operation
                        end # end parsecomponents
                        
                        ###########################################
                        if(file_loaded("swapmaterials02.rb"))
                           menu = UI.menu("Plugins");
                           menu.add_item("Parse Model") {parsecomponents}
                        end
                        #------------------------------------------
                        
                        file_loaded("swapmaterials02.rb")
                        

                        TIG

                        1 Reply Last reply Reply Quote 0
                        • D Offline
                          Doi
                          last edited by 30 Apr 2010, 10:30

                          Wow TIG,

                          thank you so much! Both edits work a treat πŸ˜„, but yes yours is definitely more succinct - I have always had issues with my code being a tad too verbose, and possibly missing the trees for the forest... 😳

                          After my previous post, I was thinking it did seem odd that I wasn't working directly with the definition, but I'm sure I would never have found it without the help β˜€

                          Thanks again - now onto the next tweak...

                          Cheers,
                          Doi!

                          1 Reply Last reply Reply Quote 0
                          • 1 / 1
                          1 / 1
                          • First post
                            1/12
                            Last post
                          Buy SketchPlus
                          Buy SUbD
                          Buy WrapR
                          Buy eBook
                          Buy Modelur
                          Buy Vertex Tools
                          Buy SketchCuisine
                          Buy FormFonts

                          Advertisement