sketchucation logo sketchucation
    • Login
    1. Home
    2. oajfh
    ℹ️ Licensed Extensions | FredoBatch, ElevationProfile, FredoSketch, LayOps, MatSim and Pic2Shape will require license from Sept 1st More Info
    O
    Offline
    • Profile
    • Following 0
    • Followers 0
    • Topics 6
    • Posts 22
    • Groups 1

    oajfh

    @oajfh

    10
    Reputation
    1
    Profile views
    22
    Posts
    0
    Followers
    0
    Following
    Joined
    Last Online

    oajfh Unfollow Follow
    registered-users

    Latest posts made by oajfh

    • RE: Sketchup internal matrix transformation error compensation ?

      I don't have any code right now, I will once I have access to it though, which should be in a couple of days.

      The general procedure works like this though.

      Before anything else, I store the initial orientation by making an axes type Transformation. Something like this if memory serves well :

      xaxis_ = cInst.transformation.xaxis
      		yaxis_ = cInst.transformation.yaxis
      		zaxis_ = cInst.transformation.zaxis
      		@transform = Geom;;Transformation.axes(Geom;;Point3d.new(0,0,0),Geom;;Vector3d.new(xaxis_.x,xaxis_.y,xaxis_.z),Geom;;Vector3d.new(yaxis_.x,yaxis_.y,yaxis_.z),Geom;;Vector3d.new(zaxis_.x,zaxis_.y,zaxis_.z))
      

      The translations to move to and from the origin are created using the center of the bounds of the component.

      The origin to object axes are also calculated with an axes type Transformation. I use the inverse to return from global to local.

      The rotation part of the external transformation is created from an array, with indices 3, 7, 11, 12, 13, 14 set to 0 and index 15 set to 1. Said array comes from extracting numbers from a string. I thought there might be some bug or some accuracy loss here, but it's a double to float conversion on mostly small numbers, and checking the orthogonality of the rotation component gives no error before the 12th digit.

      The translation part (which is global, not relative to the component, btw) is used to make a vector used to make a Transformation. I've had the skewing even when this was 0, though.

      And then it goes like this :

      -Store initial transformation.

      When transformation is received :
      -move to origin
      -switch from object to origin axes
      -Compensate the initial transformation if there is one.
      -Apply rotation
      -apply the inverse of the initial transformation
      -go to object axes
      -Apply translation (global)
      -Move back from the origin

      Granted, it's not the best workflow. However, given the accuracy I seem to have on the sole matrix that isn't created within SU, I don't understand how the skewing happens, particularly when multiplying all these external matrices together yields an error that is so tiny.

      posted in Developers' Forum
      O
      oajfh
    • Sketchup internal matrix transformation error compensation ?

      Greetings.

      I've been doing some strange things to my poor Sketchup installation these past few days. Recently, I tried sending a few dozen transformation matrices obtained by external means, and appyling them to a component and here's what happened :

      -These transformations are local, i.e. I need to move my component back to the origin, rotate it back to the last transformation I kept in memory, compensate once more so that the axes are aligned to the global axes, multiply by the transformation, and then multiply by the inverses of the first three matrices.

      -I handled that in Sketchup, which is probably not the best choice. However, all the matrices except for the transformation generated from elsewhere, are created using transformation.new, whether it be a new axes transformation, a new translation, or a new rotation, each time with the corresponding constructor.

      -After a few hundred, sometimes a few dozen only, transformations, the component instance's transformation matrix's rotation component (that was a mouthful) would completely stop being orthogonal, and the component would scale off to infinity in one direction and to zero in the others. I.e, numerical unstability, which I didn't think would happen.

      -The rotation matrices are double precision. After multiplying a few hundred of them together outside of SU, the relative error I get is much much smaller than the one in SU. It is around 10^-4 mm , which is still almost negligible, and definitely not visible to the human eye.

      So what did I do ? I added a simple method for compensating the 'deorthogonalisation' of the component instance transformation, and the error stays at minuscule amounts. I'm worried that some form of desynchronisation and slight numerical inaccuracy might happen if I apply thousands of transformations, but so far I haven't seen any major or even minor differences. It therefore seems not to be a problem anymore, for me anyway.

      But, I'm a curious individual. So my question : Does SU handle this deorthogonalisation internally and if so, how ? I'm assuming this phenomenon can happen regardless of where the transformations come from, and is either compensated or made to never happen (using specific constraints, or a different internal representation, perhaps). If it is the former, then why does this desynchronisation happen when sending external transformations ?

      I hope I'm being clear enough. Good day to ye, anyway.

      posted in Developers' Forum
      O
      oajfh
    • State of Observers ?

      Hi all.

      A feature I've been thinking about in a project is synchronising an item in SU with another item in another program.

      Sending information to and from isn't a problem. What I'm curious about is the Observers I should use.

      Since no Observer (as far as I've seen) keeps directly track of entity positions or orientations, one way I could think of that'd enable me to do so would be by combining a Tool Observer (OnButtonUp and OnButtonDown) and an EntityObserver (OnEntityChange), and making sure the right tool is selected. That way I could send a transformation information whenever the user completes a move, scale or rotate action.

      Does this seem like the most natural way to you ? Are there any latent bugs (seems like Observers have had problems in past versions, I can't seem to find more recent information) or potential problems to this approach (I've read up on a few common pitfalls but don't know much more) ?

      posted in Developers' Forum
      O
      oajfh
    • RE: Vertex Normals... ?

      😳

      Yes, you are absolutely right. I hadn't quite understood what Thomthom meant. Sorry for dragging this topic on for so long.

      posted in Developers' Forum
      O
      oajfh
    • RE: Vertex Normals... ?

      Well, after more experimenting, taking into account what's been said :

      
      # Original credit ; Anton_S
      # Get group/component entities.
      # @param [Sketchup;;Group, Sketchup;;ComponentInstance] entity
      # @return [Sketchup;;Entities]
      def get_entities(entity)
      	if entity.is_a?(Sketchup;;ComponentInstance)
      		return entity.definition.entities
      	else 
      		return entity.entities
      	end
      end
      
      # Original credit ; Anton_S
      # Get triangular mesh of the group.
      # @param [Sketchup;;Group, Sketchup;;ComponentInstance] entity
      # @param [Boolean] recursive Whether to include all the child groups and
      #   components.
      # @param [Boolean] transform Whether to give points in global coordinates.
      # @param [Integer] Keep face counter so as not to mess up normal exporting
      # @yield A procedure to determine whether particular child group/component
      #   should be considered a part of the collection.
      # @yieldparam [Sketchup;;Group, Sketchup;;ComponentInstance] entity
      # @yieldreturn [Boolean] Pass true to consider an entity as part of the
      #   collection. Pass false to not consider an entity as part of the
      #   collection.
      # @return [Geom;;PolygonMesh]
      def get_triangular_mesh(entity, recursive = true, transform = false,normal_array, &entity_validation)
      
        mesh = Geom;;PolygonMesh.new
        if( entity.is_a?(;;Sketchup;;Face)||entity.is_a?(;;Sketchup;;ComponentInstance)||entity.is_a?(;;Sketchup;;Group))
      	get_entities(entity).each { |e|
      		if e.is_a?(;;Sketchup;;Face)
      
      			e.mesh.polygons.each_index{ |i|
      			pts = e.mesh.polygon_points_at(i+1)
      			
      			mesh_b = e.mesh 4 #Temp face with normals
      
      			index = mesh.add_polygon(pts)
      			
      			#puts "e"
      			for k in 1..mesh_b.count_points
      				#puts "k"
      				#puts mesh_b.point_at(k) #Not global coordinates
      				#puts mesh_b.normal_at(k)
      				index = mesh.point_index(mesh_b.point_at(k)) # Get index of current point being examined
      				#puts index
      				#puts mesh.point_at(index)
      				#puts "k"
      				normal_array[index] = mesh_b.normal_at(k) # Set that point's normal to the current point's normal's value
      			end
      			#puts "j"
            }
      		elsif recursive && (e.is_a?(;;Sketchup;;Group) || e.is_a?(;;Sketchup;;ComponentInstance)) && entity_validation.call(e)
      			new_array = []
      			mesh2 = get_triangular_mesh(e, true, true, new_array, &entity_validation)
      			mesh2.polygons.each_index { |i|
      			index = mesh.add_polygon(mesh2.polygon_points_at(i+1))
      
      			mesh2.points.each_with_index{|point, index|
      				ind = mesh.point_index(point)
      				normal_array[ind]= new_array[index]
      			}
      		}
          end
        }
        mesh.transform!(entity.transformation) if transform
      	for l in 1..normal_array.length-1 #index 0 not used so length is 1 more than expected
      		#puts l
      		normal_array[l].transform!(entity.transformation) if transform
      	end
        end
        return mesh
      end
      
      
      normal_array = [] # Contains the VERTEX normals.
      mesh = get_triangular_mesh(group, true, true,normal_array){ |e| true }
      
      
      

      (This code is bad and unoptimised, I'm aware of that. I'm a terrible programmer)

      I'm not sure what to think of this.

      If I look at what vertex normals are returned during recursion, I occasionally get different normals for what appears to be the same vertex, and I don't know why. For a cube, I only get global axis-aligned vectors, which isn't really what I was expecting.

      posted in Developers' Forum
      O
      oajfh
    • RE: Vertex Normals... ?

      I'm building it from an existing component, so I'd simply be copying existing normals. Why would the vertex normals be incorrect ?

      Also, are you sure about the point to point comparison ? If you create different groups within a component, won't it duplicate the points ? I was getting different results after exploding groups and creating the mesh after making a component out of the exploded ex-groups. So the comparison might not only be coordinate-based.

      Thanks for the tip on performance, too. Will come in handy.

      posted in Developers' Forum
      O
      oajfh
    • RE: Vertex Normals... ?

      Thanks for the tips Dan.

      My code recovers points rather than vertices from a component (it's based off what Anton_S posted in my topic about PolygonMesh triangulation).

      ThomThom, doesn't the add_polygon method simply add any new points at the end of the point array ? That's the behaviour it's exhibited for me so far, so wouldn't applying what Dan said be alright ?

      On another note, the vertex normal seems to be local to the transformation the face's parent possesses. It complexifies the recursion somewhat to recover the transformation at that point in the iteration.

      I'll just post my code, it'll be clearer for you. Thanks again to the both of you and Anton_S, by the way.

      
      # Original credit ; Anton_S
      # Get group/component entities.
      # @param [Sketchup;;Group, Sketchup;;ComponentInstance] entity
      # @return [Sketchup;;Entities]
      def get_entities(entity)
      	if entity.is_a?(Sketchup;;ComponentInstance)
      		return entity.definition.entities
      	else 
      		return entity.entities
      	end
      end
      
      # Original credit ; Anton_S
      # Get triangular mesh of the group.
      # @param [Sketchup;;Group, Sketchup;;ComponentInstance] entity
      # @param [Boolean] recursive Whether to include all the child groups and
      #   components.
      # @param [Boolean] transform Whether to give points in global coordinates.
      # @param [Integer] Keep face counter so as not to mess up normal exporting
      # @yield A procedure to determine whether particular child group/component
      #   should be considered a part of the collection.
      # @yieldparam [Sketchup;;Group, Sketchup;;ComponentInstance] entity
      # @yieldreturn [Boolean] Pass true to consider an entity as part of the
      #   collection. Pass false to not consider an entity as part of the
      #   collection.
      # @return [Geom;;PolygonMesh]
      def get_triangular_mesh(entity, recursive = true, transform = false,normal_array, &entity_validation)
      
        mesh = Geom;;PolygonMesh.new
        if( entity.is_a?(;;Sketchup;;Face)||entity.is_a?(;;Sketchup;;ComponentInstance)||entity.is_a?(;;Sketchup;;Group))
      	get_entities(entity).each { |e|
      		if e.is_a?(;;Sketchup;;Face)
      
      			e.mesh.polygons.each_index{ |i|
      			pts = e.mesh.polygon_points_at(i+1)
      			
      			mesh_b = e.mesh 4
      
      			index = mesh.add_polygon(pts) # Note ; index not necessary here
      		
      			normal_array << e.normal # add face normal
      			
      			#puts "e"
      			for k in 1..mesh_b.count_points
      				#puts mesh_b.point_at(k) #Not global coordinates
      				#puts mesh_b.normal_at(k) #Not global coordinates... ?
      			end
      			puts "j"
            }
      		elsif recursive && (e.is_a?(;;Sketchup;;Group) || e.is_a?(;;Sketchup;;ComponentInstance)) && entity_validation.call(e)
      			new_array = []
      			mesh2 = get_triangular_mesh(e, true, true, new_array, &entity_validation)
      			mesh2.polygons.each_index { |i|
      			index = mesh.add_polygon(mesh2.polygon_points_at(i+1))
      			normal_array[index] = new_array[i] # Doesn't seem to be overriding previous values
      			#counter=counter+1
      			#puts counter
      		}
          end
        }
        mesh.transform!(entity.transformation) if transform
        end
        return mesh
      end
      
      
      group = Sketchup.active_model.selection[0] # Lazy component recovery
      
      #TODO begin end
      
      normal_array = [] # Contains the face normals.
      mesh = get_triangular_mesh(group, true, true,normal_array){ |e| true }
      puts mesh.points
      pt = Geom;;Point3d.new(100,0,0)
      mesh.transform!(pt) # Move triangles 100 units on xaxis from original component.
      Sketchup.active_model.entities.add_faces_from_mesh(mesh, 0)
      
      
      #puts mesh.points # translated mesh
      
      

      It isn't super fast though.

      Actually, perhaps the simplest would be to traverse the triangulation a second time ? The generated mesh is all in global coordinates, so the normals would be as well.

      I could probably do that as a temporary solution, until performance becomes too critical and I have to do stuff out of Ruby. I'm still prototyping, so I just need a reliable way of recovering the normals for the moment.

      posted in Developers' Forum
      O
      oajfh
    • RE: Vertex Normals... ?

      I'm using SU 2015.

      I was just confused mostly by the documentation, heh -I'm still a rather inexperienced Ruby and SU coder, and when I wanted to look it up and check the methods the SU doc site was down, so I thought I might as well ask here and learn a little more.

      If vertex normals can be safely recovered, then perhaps I should use those.

      Hmm. How would that fare performance-wise ? If I want to recover vertex normals, I probably end up checking vertexes multiple times and making sure I don't get a normal from the same vertex more than once, but on the other hand calculating face normals is faster than calculating weighted vertex normals.

      posted in Developers' Forum
      O
      oajfh
    • RE: Vertex Normals... ?

      Ok, thanks.

      posted in Developers' Forum
      O
      oajfh
    • RE: Vertex Normals... ?

      Thanks ThomThom, I had seen that thread but was wondering if things had changed.

      In any case, I'll work on it outside of SU. I don't think there are many people who would need vertex normals while working in SU, since they are mostly used for lighting and rendering (as far as I know, anyway, but I don't know much).
      However, perhaps a way to recover them in exporters could be useful, I dunno.

      Also, just in case, could you clarify this statement :
      "PolygonMesh will in fact return vector normal. It depend on the edges connected are soft+smooth or note."

      So they do return vertex normals... ? I thought it was a normal linked to the surface. Sorry, I'm confused. I'm not sure I understood what you meant completely, could you possibly expand on it ?

      [Edit] Never mind, I think I got it. I can recover vertex normals but they might not be reliable for now ?
      In that case, I guess I will recover Face normals for now.

      posted in Developers' Forum
      O
      oajfh