Computing shadow of building footprint

mit matplotlib, NumPy, pandas, SciPy, SymPy und weiteren mathematischen Programmbibliotheken.
100ri
User
Beiträge: 4
Registriert: Donnerstag 8. September 2016, 18:29

Computing shadow of building footprint

Beitragvon 100ri » Donnerstag 8. September 2016, 18:37

Dear All
I'm an international PhD student in the field of Climate change at Humboldt University. For my research I#m using ArcGIS 10.3. I need a tool which By luck I found the source as a Phyton code on the web:
http://gis.stackexchange.com/questions/ ... -arcgis-de
I am interested in importing this in ArcGIS as a toolbox. Its a code for computing the shadow of building footprint, considering the height of the building, at a certain date and time of the year. Unfortunately and sadly I have knowledge on scripting. Therefore I was wondering if someone could help me with that, or at least to check whether this code is correct? I appreciate your help in advance.

Cheers

CoDe:

  1. import arcpy
  2. import os
  3. import math
  4.  
  5. def message(msg, severity=0):
  6.     # Adds a Message (in case this is run as a tool)
  7.     # and also prints the message to the screen (standard output)
  8.     #
  9.     print msg
  10.  
  11.     # Split the message on \n first, so that if it's multiple lines,
  12.     #  a GPMessage will be added for each line
  13.     try:
  14.         for string in msg.split('\n'):
  15.             # Add appropriate geoprocessing message
  16.             #
  17.             if severity == 0:
  18.                 arcpy.AddMessage(string)
  19.             elif severity == 1:
  20.                 arcpy.AddWarning(string)
  21.             elif severity == 2:
  22.                 arcpy.AddError(string)
  23.     except:
  24.         pass
  25.  
  26. def main():
  27.     arcpy.env.overwriteOutput=True
  28.  
  29.     # Read in parameters
  30.     inputFC = arcpy.GetParameterAsText(0)
  31.     outputFC = arcpy.GetParameterAsText(1)
  32.     heightfield = arcpy.GetParameterAsText(2) #Must be in the same units as the coordinate system!
  33.     azimuth = math.radians(float(arcpy.GetParameterAsText(3))) #Must be in degrees
  34.     altitude = math.radians(float(arcpy.GetParameterAsText(4))) #Must be in degrees
  35.  
  36.     # Specify output field name for the original FID
  37.     origfidfield = "ORIG_FID"
  38.  
  39.     # Get field names
  40.     desc = arcpy.Describe(inputFC)
  41.     shapefield = desc.shapeFieldName
  42.     oidfield = desc.oidFieldName
  43.  
  44.     #Output
  45.     message("Creating output feature class %s ..." % outputFC)
  46.     arcpy.CreateFeatureclass_management(
  47.         os.path.dirname(outputFC),
  48.         os.path.basename(outputFC),
  49.         'POLYGON', "", "", "",
  50.         desc.spatialReference if not arcpy.env.outputCoordinateSystem else "")
  51.     arcpy.AddField_management(outputFC, origfidfield, "LONG")
  52.     inscur = arcpy.InsertCursor(outputFC)
  53.  
  54.     # Compute the shadow offsets.
  55.     spread = 1/math.tan(altitude) #outside loop as it only needs calculating once
  56.  
  57.     count = int(arcpy.GetCount_management(inputFC).getOutput(0))
  58.     message("Total features to process: %d" % count)
  59.  
  60.     searchFields = ",".join([heightfield, oidfield, shapefield])
  61.     rows = arcpy.SearchCursor(inputFC, "", "", searchFields)
  62.  
  63.     interval = int(count/10.0) # Interval for reporting progress every 10% of rows
  64.  
  65.     # Create array for holding shadow polygon vertices
  66.     arr = arcpy.Array()
  67.     for r, row in enumerate(rows):
  68.         pctComplete = int(round(float(r) / float(count) * 100.0))
  69.         if r % interval == 0:
  70.             message("%d%% complete" % pctComplete)
  71.         oid = row.getValue(oidfield)
  72.         shape = row.getValue(shapefield)
  73.         height = float(row.getValue(heightfield))
  74.  
  75.         # Compute the shadow offsets.
  76.         x = -height * spread * math.sin(azimuth)
  77.         y = -height * spread * math.cos(azimuth)
  78.  
  79.         # Initialize a list of shadow polygons with the original shape as the first
  80.         shadowpolys = [shape]
  81.  
  82.         # Compute the wall shadows and append them to the list
  83.         for part in shape:
  84.             for i,j in enumerate(range(1,part.count)):
  85.                 pnt0 = part[i]
  86.                 pnt1 = part[j]
  87.                 if pnt0 is None or pnt1 is None:
  88.                     continue # skip null points so that inner wall shadows can also be computed
  89.  
  90.                 # Compute the shadow offset points
  91.                 pnt0offset = arcpy.Point(pnt0.X+x,pnt0.Y+y)
  92.                 pnt1offset = arcpy.Point(pnt1.X+x,pnt1.Y+y)
  93.  
  94.                 # Construct the shadow polygon and append it to the list
  95.                 [arr.add(pnt) for pnt in [pnt0,pnt1,pnt1offset,pnt0offset,pnt0]]
  96.                 shadowpolys.append(arcpy.Polygon(arr))
  97.                 arr.removeAll() # Clear the array so it can be reused
  98.  
  99.         # Dissolve the shadow polygons
  100.         dissolved = arcpy.Dissolve_management(shadowpolys,arcpy.Geometry())[0]
  101.  
  102.         # Insert the dissolved feature into the output feature class
  103.         newrow = inscur.newRow()
  104.         newrow.setValue(origfidfield, oid) # Copy the original FID value to the new feature
  105.         newrow.shape = dissolved
  106.         inscur.insertRow(newrow)
  107.  
  108.         del row, newrow, shadowpolys, dissolved
  109.     del inscur, rows
  110.  
  111. if __name__ == "__main__":
  112.     main()
Benutzeravatar
noisefloor
User
Beiträge: 1650
Registriert: Mittwoch 17. Oktober 2007, 21:40
Wohnort: Görgeshausen
Kontaktdaten:

Re: Computing shadow of building footprint

Beitragvon noisefloor » Freitag 9. September 2016, 20:25

Hi,

well, in your initial post the actual problem respectively the question is missing.

Did you run the code you posted? If so, what's the result? Any error messages? Did your computer explode (probably and hopefully not ;-) )? ...?

Besides that, the language of this board is German. Basically it's not forbidden to post requests in other languages (AFAIK), but the number of answers you get me be limited.

Regards, noisefloor
Benutzeravatar
BlackJack
Moderator
Beiträge: 32226
Registriert: Dienstag 25. Januar 2005, 23:29
Wohnort: Berlin
Kontaktdaten:

Re: Computing shadow of building footprint

Beitragvon BlackJack » Freitag 9. September 2016, 22:04

@100ri: I think more limiting than the language is using ArcGIS. I'm pretty confident more users here have no problem reading and answering questions in English, than ones who have experience with ArgGIS.

Any general programming (with Python) or Python specific questions are likely to get you answers, but if it involves ArgGIS specific stuff chances of answers are higher in a ArcGIS related forum or community. Like GIS StackExchange where you found that solution.

Regarding the correctness: That's a really hard question to answer. Proving a programm correct is difficult, often even if all the external functionality, in this case `arcpy`, is known.

It compiles. The answer on GIS StackExchange got a 100 points bounty award. There's no comment to that answer saying it doesn't work. So give it a try.

From a Python programmer's point of view there are a couple of ”bad” things in that program:

”Naked” ``except:``\s without one or more specific expected Exception is a bad idea. The handling part is just a ``pass`` so this is a sink of errors. They just get ignored, even ones you might not want to ignore.

The ``del`` statements are all unnecessary. Even worse: they might mislead a reader not fluent in Python into thinking there are objects deleted and memory freed by those statements. ``del`` on bare names deletes those *names*, not the *objects* that are assigned to the names. Such an object may or may not be freed after a ``del`` of the (only) name referencing it. There's no guarantees as to when or even if that happens. All deleted names in the loop are reassigned anyway and deleting names at the end of a function when they fall out of scope anyway just doesn't make any sense at all.

The best way of ”managing memory” in Python is to write functions and limit the scope of names this way. Everything not bound to a name or referenced from a data structure is fair game to the garbage collector.

List comprehensions (LCs) are not meant to write an ordinary loop, used for side effects, in one line. Additionally the abuse of that language feature would be even unnecessary if one wants to write the loop in a single line because this would be possible without the LC syntax.

The `main()` function is much too long. Over 30 local names are used there. That's more than the average person can keep in mind at once. It's much easier to read, reason and talk about a couple of simple, well named functions that are doing a small subtask.

Well named is something that's also important for other objects besides functions. Try to follow the Style Guide for Python Code. Avoid cryptic abbrevations and smushed together words without underscores. `inscur` is an example of both points. Better would be `insert_cursor`. Don't think about saving keystrokes when writing but about readability. Source code is much more often read than written. :-)

The `severity` argument of `message()` isn't used, so the function could be written a bit simpler.

Comments explaining what a function is doing are better set as DocStrings instead of just comments.

Getting at `pnt0` and `pnt1` is a bit weird. Instead of a simple counter and accessing via the counter and the counter + 1, or using some elegant `itertools` solution, there is this hybrid of iterators and old school indexing.

`pctComplete` is computed for each row but used only after a batch worth 10% of rows has been processed.

I personally would avoid ``continue`` as much as possible. It's an unconditional jump to the loop start not reflected in the code structure. And it may make it harder to factor out parts or the whole loop body into function(s). In the given program it would be very easy to change the code to get rid of the ``continue``.
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. — Brian W. Kernighan
100ri
User
Beiträge: 4
Registriert: Donnerstag 8. September 2016, 18:29

Re: Computing shadow of building footprint

Beitragvon 100ri » Montag 12. September 2016, 15:21

noisefloor hat geschrieben:Hi,

well, in your initial post the actual problem respectively the question is missing.

Did you run the code you posted? If so, what's the result? Any error messages? Did your computer explode (probably and hopefully not ;-) )? ...?

Besides that, the language of this board is German. Basically it's not forbidden to post requests in other languages (AFAIK), but the number of answers you get me be limited.

Regards, noisefloor


Thank you very much for your response. I understand that my options will be limited, but studying in Germany I though posting my question here as well :) The initial question as mentioned, would have been, to see if the script is good and well written or not...
100ri
User
Beiträge: 4
Registriert: Donnerstag 8. September 2016, 18:29

Re: Computing shadow of building footprint

Beitragvon 100ri » Montag 12. September 2016, 15:27

BlackJack hat geschrieben:@100ri: I think more limiting than the language is using ArcGIS. I'm pretty confident more users here have no problem reading and answering questions in English, than ones who have experience with ArgGIS.

Any general programming (with Python) or Python specific questions are likely to get you answers, but if it involves ArgGIS specific stuff chances of answers are higher in a ArcGIS related forum or community. Like GIS StackExchange where you found that solution.

Regarding the correctness: That's a really hard question to answer. Proving a programm correct is difficult, often even if all the external functionality, in this case `arcpy`, is known.

It compiles. The answer on GIS StackExchange got a 100 points bounty award. There's no comment to that answer saying it doesn't work. So give it a try.

From a Python programmer's point of view there are a couple of ”bad” things in that program:

”Naked” ``except:``\s without one or more specific expected Exception is a bad idea. The handling part is just a ``pass`` so this is a sink of errors. They just get ignored, even ones you might not want to ignore.

The ``del`` statements are all unnecessary. Even worse: they might mislead a reader not fluent in Python into thinking there are objects deleted and memory freed by those statements. ``del`` on bare names deletes those *names*, not the *objects* that are assigned to the names. Such an object may or may not be freed after a ``del`` of the (only) name referencing it. There's no guarantees as to when or even if that happens. All deleted names in the loop are reassigned anyway and deleting names at the end of a function when they fall out of scope anyway just doesn't make any sense at all.

The best way of ”managing memory” in Python is to write functions and limit the scope of names this way. Everything not bound to a name or referenced from a data structure is fair game to the garbage collector.

List comprehensions (LCs) are not meant to write an ordinary loop, used for side effects, in one line. Additionally the abuse of that language feature would be even unnecessary if one wants to write the loop in a single line because this would be possible without the LC syntax.

The `main()` function is much too long. Over 30 local names are used there. That's more than the average person can keep in mind at once. It's much easier to read, reason and talk about a couple of simple, well named functions that are doing a small subtask.

Well named is something that's also important for other objects besides functions. Try to follow the Style Guide for Python Code. Avoid cryptic abbrevations and smushed together words without underscores. `inscur` is an example of both points. Better would be `insert_cursor`. Don't think about saving keystrokes when writing but about readability. Source code is much more often read than written. :-)

The `severity` argument of `message()` isn't used, so the function could be written a bit simpler.

Comments explaining what a function is doing are better set as DocStrings instead of just comments.

Getting at `pnt0` and `pnt1` is a bit weird. Instead of a simple counter and accessing via the counter and the counter + 1, or using some elegant `itertools` solution, there is this hybrid of iterators and old school indexing.

`pctComplete` is computed for each row but used only after a batch worth 10% of rows has been processed.

I personally would avoid ``continue`` as much as possible. It's an unconditional jump to the loop start not reflected in the code structure. And it may make it harder to factor out parts or the whole loop body into function(s). In the given program it would be very easy to change the code to get rid of the ``continue``.


Thanks A lot indeed for your complete response. I don't know if you have ever been eager to proceed with something, but missing the tool to go further...? Well currently I'm at that place :D at the moment there is not source for me other than the code which I found by luck on the web to proceed with my research. And I understand your perceptive point of view regarding ArcGIS.
As I have, unfortunately, not background on scripting at all, I was wondering if I could ask you kindly to apply your comments with the code I have posted? Then at least I have the chance to compare the output of the revised code as well and integrate the best result. I appreciate if that will be an option... However I understand one's limit as well. Cheers
Benutzeravatar
BlackJack
Moderator
Beiträge: 32226
Registriert: Dienstag 25. Januar 2005, 23:29
Wohnort: Berlin
Kontaktdaten:

Re: Computing shadow of building footprint

Beitragvon BlackJack » Mittwoch 14. September 2016, 19:52

@100ri: I don't think its a good idea to change the code unless you've confirmed that it actually solves your problem. And even then the points I've made don't change the functionality but ”just” the quality of the code regarding readability and maintainability. Unless you want to work on the program, which requires programming skills that you don't have as you said, it doesn't make much sense to refactor the code.
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. — Brian W. Kernighan
100ri
User
Beiträge: 4
Registriert: Donnerstag 8. September 2016, 18:29

Re: Computing shadow of building footprint

Beitragvon 100ri » Montag 19. September 2016, 11:57

BlackJack hat geschrieben:@100ri: I don't think its a good idea to change the code unless you've confirmed that it actually solves your problem. And even then the points I've made don't change the functionality but ”just” the quality of the code regarding readability and maintainability. Unless you want to work on the program, which requires programming skills that you don't have as you said, it doesn't make much sense to refactor the code.




Vielen vielen dank für Ihren Antwort anyways :)
Benutzeravatar
BlackJack
Moderator
Beiträge: 32226
Registriert: Dienstag 25. Januar 2005, 23:29
Wohnort: Berlin
Kontaktdaten:

Re: Computing shadow of building footprint

Beitragvon BlackJack » Montag 19. September 2016, 12:17

FYI: Packt offers the e-book „Programming ArcGIS 10.1 with Python Cookbook“ (PDF/EPub/Mobi) for the next 11 hours for free: https://www.packtpub.com/packt/offers/free-learning
Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. — Brian W. Kernighan

Zurück zu „Wissenschaftliches Rechnen“

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder