sketchucation logo sketchucation
    • Login
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info

    How to see the results of this method?

    Scheduled Pinned Locked Moved Developers' Forum
    8 Posts 4 Posters 769 Views 4 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.
    • C Offline
      CEIT81729
      last edited by

      def sum_area( material, entities, tr = Geom;;Transformation.new )
        area = 0.0
        for entity in entities
          if entity.is_a?( Sketchup;;Group )
            area += sum_area( material, entity.entities, tr * entity.transformation )
          elsif entity.is_a?( Sketchup;;ComponentInstance )
            area += sum_area( material, entity.definition.entities, tr * entity.transformation )
          elsif entity.is_a?( Sketchup;;Face ) && entity.material == material
            # (!) The area returned is the unscaled area of the definition.
            #     Use the combined transformation to calculate the correct area.
            #     (Sorry, I don't remember from the top of my head how one does that.)
            #
            # (!) Also not that this only takes into account materials on the front
            #     of faces. You must decide if you want to take into account the back
            #     size as well.
            area += entity.area
          end
        end
        area
      end
      

      Thank you for your help!

      1 Reply Last reply Reply Quote 0
      • TIGT Offline
        TIG Moderator
        last edited by

        Please learn to put your code in 'code' format.
        I have done it for you - edit the post to see what I did...
        To do single-lines use the 'ruby' formating [as I show below]...

        Now for your question...
        The method return the area as it completes its processing, so something like:
        my_area = sum_area( some_material, some_entities, some_transformation )
        will return a float in square-inches thus 1234.56789 - here assigned to a reference my_area
        If you run the code in the Ruby Console it should complete showing the area you want.
        Obviously to make it into some other units - e.g. m² - use a suitable conversion factor...
        my_area_m2 = sum_area( some_material, some_entities, some_transformation )*0.00064516
        The 3rd argument transformation could be passed as empty, or a 'blank' new transformation...

        TIG

        1 Reply Last reply Reply Quote 0
        • C Offline
          CEIT81729
          last edited by

          But it seems no way to calculate the area...

          1 Reply Last reply Reply Quote 0
          • TIGT Offline
            TIG Moderator
            last edited by

            I don't understand your comment.
            Please try and explain it another way...
            I can get your code to report the area of selected faces or faces inside a group etc, thus:
            my_area_m2 = sum_area( nil, Sketchup.active_model.selection )*0.00064516
            This works for NO material [ nil].
            If you want to get another material you must pass it as a 'material', perhaps found 'by name' thus:
            m2 = 0.0 mat = Sketchup.active_model.materials['Red'] m2 = sum_area(mat, Sketchup.active_model.selection) if mat

            TIG

            1 Reply Last reply Reply Quote 0
            • sdmitchS Offline
              sdmitch
              last edited by

              @ceit81729 said:

              But it seems no way to calculate the area...

              This is a rather interesting problem. If you create a group, select it and run code that gets the area of say "red" material, then scale the group and repeat the code, you will get the same area. So somehow the scale factors have to be considered but how and which ones? If you open the group for edit and run the code, you will get the correct area of the scaled face.

              Nothing is worthless, it can always be used as a bad example.

              http://sdmitch.blogspot.com/

              1 Reply Last reply Reply Quote 0
              • TIGT Offline
                TIG Moderator
                last edited by

                So the question is actually, "How to determine the area of a specific face, given that the face is inside a 'container' that can be scaled in any of its three axes..."

                First we can get the axes of the transformation [tr].
                xaxis = tr.xaxis yaxis = tr.yaxis zaxis = tr.zaxis
                we can also get the normal of the face.
                normal = face.normal
                We can get the three possible scaling factors for the transformation, thus:
                xscale = X_AXIS.transform(tr).length.to_f
                yscale = Y_AXIS.transform(tr).length.to_f
                zscale = Z_AXIS.transform(tr).length.to_f
                Note that these do not show negative scaling if handed etc - but for area calculations you don't want that anyway...
                Next we need to apply each of the three scaling factors to the face's area, having due regard in turn for the angle between the face.normal and each of the three axes relating to each scale factor...
                Obviously a face that is perpendicular to an axis is fully scaled as that axis's scaling, but one that is parallel to the axes is unaffected by that axis's scaling - a box scaled in the Z by 2.0 has no scaling of its faces that have a normal parallel to the Z_AXIS, but the side faces will scale in the other axes...
                Something like:
                ascaler = 1.0 xscaler = Math.sin(xaxis.angle_between(normal)) ascaler *= xscaler*xscale if xscaler > 0 yscaler = Math.sin(yaxis.angle_between(normal)) ascaler *= yscaler*yscale if yscaler > 0 zscaler = Math.sin(zaxis.angle_between(normal)) ascaler *= zscaler*zscale if zscaler > 0 area *= ascaler
                Note - I haven't tested this !
                But you should get the idea...

                TIG

                1 Reply Last reply Reply Quote 0
                • J Offline
                  Jim
                  last edited by

                  Do a search on this forum for "binormal" and see AdamB's code.

                  Hi

                  1 Reply Last reply Reply Quote 0
                  • TIGT Offline
                    TIG Moderator
                    last edited by

                    @Jim

                    Thanks, I knew there was something somewhere - but it was six and a half years ago !
                    To précis a version of AdamB's [much cleverer] code:

                    
                    def self.face_area(mat, context, tr)
                       area = 0.0
                       context.entities.grep(Sketchup;;Group).each{|e|
                          area += self.face_area(mat, e, e.transformation)
                       }
                       context.entities.grep(Sketchup;;Component_Instance).each{|i|
                          area += self.face_area(mat, i.definition, i.transformation)
                       }
                       context.entities.grep(Sketchup;;Face).select{|f|
                          f.material == mat
                       }.each{|f|  
                          normal = f.normal
                          binormal = Geom;;Vector3d.new(normal.y, normal.z, normal.x)
                          tangent = (normal * binormal).normalize
                          areascale = (tr * binormal).length * (tr * tangent).length
                          area += ( f.area * areascale )
                       }
                       return area
                    end
                    
                    

                    The 'mat' must be a reference to a model.material [or nil]...
                    The 'context' must be either the model or a group or a definition [i.e. something that will have 'entities']
                    The transformation 'tr' must be a 'Geom::Transformation' - even it's 'blank', so the arguments are:
                    (material, model, Geom::Transformation.new()) (material, group, group.transformation) (material, instance.definition, instance.transformation)

                    The method returns the area of all faces within the context, included nested containers, and adjusts them to allow for any scaling of those containers...

                    To apply transformations of nested containers which themselves are within transformed containers etc, you need to iterate the method within itself, passing/reapplying transformations [similar to the earlier example 'sum_area' method] which I have botched in here... Note how its 'self.' assumes it's called as a method within a module.

                    TIG

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

                    Advertisement