Check point for shadow at given day/ime

Im hoping to be able to somehow programmatically check a certain point on a model to see if there is a shadow cast on it at a given time of day, Ive looked into the ruby class ‘shadowInfo’ but that doesnt seem to be the solution. Any thoughts?

First you should set your location, date and time in ShadowInfo. It should be sufficient to set Latitude, Longitude and TZOffset but you might want to change also city name and country. Then you set the time in Sketchup.active_model.shadow_info["ShadowTime"]. Remember to define a UTC time to assign the correct time independently by the time zone. Of course you can do this also from the UI: Model/info and Window/Shadows.

Sketchup.active_model.shadow_info["SunDirection"] will give you the Vector3d representing the direction of the sun at the current time and location.

You can then use Model.raytest with your point and the sun direction. The test will return the first object intersected by the ray. If it returns nil you see the sun from the point, if it returns something else the point is in shade.

1 Like

It is a bit more complicated. Both the face and it’s parent context must have their casts_shadows? property set true. If not, a loop must be repeated firing a new ray from the strike point up the sunward vector, and the test repeated.

Try this:

module TestPoint

  def self.in_shadow?( point, verbose=false )
    #
    # point   : an array of 3 Numerics || a Geom::Point3d object.
    # verbose : true || false
    #
    #
    mod  = Sketchup::active_model
    info = mod.shadow_info
    direction_towards_sun = info["SunDirection"]
    ray  = [ point, direction_towards_sun ]
    ignore_hidden_geometry = false # default for raytest() is true
    #
    retval = false
    result = true
    #
    until result.nil? || result == false ||
    (result.is_a?(Array) && result.empty?)
      #
      if verbose
        puts "...\nFiring sunward ray..."
      end
      result = mod.raytest( ray, ignore_hidden_geometry )
      #
      if !result || !result.is_a?(Array)
      (result.is_a?(Array) && result.empty?)
        retval = false
        result = nil
        if verbose
          puts "... NO HIT"
        end
        break # outta da' loop
      else
        #
        strike_point, stricken_objects = result
        #
        obj = stricken_objects.last
        if obj.is_a?(Sketchup::Face) && obj.parent != mod &&
        stricken_objects.size > 1
          parent = stricken_objects[-2]
        else
          parent = nil
        end
        #
        if verbose
          puts "... OBJECT STRUCK. \n..."
          puts "  <#{obj.class.name}> casts_shadows? (#{obj.casts_shadows?})"
          puts "  Parent <#{parent.class.name}> casts_shadows? (#{parent.casts_shadows?})" if !parent.nil?
        end
        if obj.casts_shadows? && parent.nil? ||
        obj.casts_shadows? && parent.casts_shadows?
          retval = true
          result = nil
          if verbose
            puts "  Point (#{ray[0].x},#{ray[0].y},#{ray[0].z}) in shadow? (TRUE)"
          end
          break
        else
          if verbose
            puts "  Point (#{ray[0].x},#{ray[0].y},#{ray[0].z}) in shadow? (unknown)"
          end
          ray = [ strike_point, direction_towards_sun ]
          # We must loop & retest from strike point ...
        end
        #
      end
      #
    end # until loop
    #
    if verbose
      puts "...\nCONCLUSION: Point (#{point.x},#{point.y},#{point.z}) in shadow? (#{retval.to_s.upcase})"
    end
    return retval
    #
  end ###

end

Here is a test model with a couple of test points on the floor. One is in the shadow of the wall. The other is in the sunlight cast through the window (whose faces and group container are set NOT to cast shadows.)
ShadowCasting.skp (40.6 KB) (SKPv14)

2 Likes

Just as a note, in the sample code it tests for striking a face. It may be possible to strike an edge that is set to cast shadows. So you could modify the code:

if (obj.is_a?(Sketchup::Face) || obj.is_a?(Sketchup::Edge)) && obj.parent != mod &&

Hi,

Sorry for digging this up.
I am trying to write my first SU plugin, whose goal is to tell at a given time if an object of a building (a window for instance) receives a sun ray or not. I used Dan’s procedure but I only get “true” return values. I guess it’s because the ray cast method returns true if the point is inside the object and stricken object is itself, am I right ?

I’d recommend starting a new thread, including some code snippet of what you have right now. The more concrete examples you can produce the easier it is to understand the question and its context.

Most especially because this topic has been marked by the original topic starter as solved.

You can create a related topic thread by going through the topic’s “Share” link dialog (button at bottom of thread and bottom of first post) and clicking the “+ New Topic” button. This will link and reference the related “source” topic, and put a note link at the top (of your new topic) like “Continuing from ‘Topic name’ …”

1 Like