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

    Temporarility Changing Materials

    Scheduled Pinned Locked Moved Developers' Forum
    7 Posts 3 Posters 299 Views 3 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.
    • J Offline
      joshb
      last edited by

      Hi,
      I've got an implementation question I was hoping I could get some guidance on.

      I'm implementing a custom view mode whereby I switch up the color and/or texture of specific entities based on attributes. The first part, being able to change to a new material was pretty straight forward, but I'm having trouble being able to restore the original material.

      My initial thought was to temporarily place the entities original material within its attribute dictionary, and then pull it out and restore it when the user exits the custom view mode. Right now, for some reason the material comes out of the attribute dictionary null. I'm thinking this maybe a ref count issue (the object on the dictionary gets deleted when replaced with a new one)... I've tried putting a clone and dup of the material on the attribute dictionary but neither of those methods work either.

      Is there a best-practice for doing this sort of material swap-out? Should I be able to store materials within the attribute dictionary? Is there a proper way to clone materials aside from the standard ruby methods?

      Thanks for the help,
      Josh

      1 Reply Last reply Reply Quote 0
      • Dan RathbunD Offline
        Dan Rathbun
        last edited by

        @joshb said:

        I've tried putting a clone and dup of the material on the attribute dictionary but neither of those methods work either.

        General "rule of thumb"... clone and dup, as inherited from Ruby, are only for pure Ruby objects.

        These methods do not work for C++ objects (that have Ruby access wrappers.)
        So.. a Sketchup class must purposely implement a custom clone and/or dup method, for it to work.
        Refering to the API method index, you will see that only Geom::Point3d, Geom::Transformation and Geom::Vector3d, have custom API clone() methods defined.

        I'm not here much anymore.

        1 Reply Last reply Reply Quote 0
        • Dan RathbunD Offline
          Dan Rathbun
          last edited by

          Now.. you cannot store a reference to a Material object directly.. basically an AttributeDictionary needs to be able to convert to String (or perhaps marshal,) the object. (But normally only Ruby base classes, can do this by default.)

          You can store the Material name into the attribute (which is a String,)... then when restoring, use that String name, to retreive the Material object from the Materials collection.

          ` # assume a local ref dict pointing at one

          of the ent's attribute dictionaries:

          dict['prev_matl']= ent.material.name

          do your viewing thangy

          matls = model.materials
          prev_matl = dict['prev_matl']
          ent.material= matls[prev_matl]`

          The other way would be to store the obj_id = ent.material.object_id.to_s into the attribute, and restore it via ObjectSpace._id2ref( obj_id.to_i )


          More info, see:
          [Info] Allowable Classes for "set_attribute"

          I'm not here much anymore.

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

            Thanks again Dan! Storing the material name works great.

            1 Reply Last reply Reply Quote 0
            • thomthomT Offline
              thomthom
              last edited by

              @joshb said:

              Thanks again Dan! Storing the material name works great.

              What if the user purges the model - and the material doesn't exist any more?

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

              1 Reply Last reply Reply Quote 0
              • Dan RathbunD Offline
                Dan Rathbun
                last edited by

                Well.. good practice would be to test the result of matls[prev_matl] to be sure it is not nil, BEFORE attempting to reset the entity's material.

                It might be advisible, to use a MaterialsObserver to be notified, actually when a Material is deleted.

                OR... he could create some temporary invisible objects (say cpoints,) that have the previous material applied, so as to prevent them from being purged. When he's done, he deletes these temporary cpoints (which he should keep an Array of refs to, just for that purpose.)

                I'm not here much anymore.

                1 Reply Last reply Reply Quote 0
                • Dan RathbunD Offline
                  Dan Rathbun
                  last edited by

                  @joshb said:

                  Thanks again Dan! Storing the material name works great.

                  Your welky!

                  However writing attributes into the model DOM.. is going to slow things down (and add extra items onto the undo stack.)

                  Since this is temporary... why not just keep the references in memory?

                  A Hash object will do fine:

                  # a new Hash to hold the material refs for each entity
                  prev_matls = {}
                  # keep the entity refs held in an Array, like;
                  ents = model.entities.to_a
                  # use Ruby's built-in Array iterator to save material refs
                  ents.each {|e| prev_matls[e]= e.material }
                  # now the hash has unique keys because each entity ref is unique
                  #
                  # your view wizard.. whatever
                  #
                  # restore them;
                  ents.each {|e|
                    (e.material= prev_matls[e]) if prev_matls[e].valid?
                  }
                  

                  I'm not here much anymore.

                  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