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.
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)
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’ …”