12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322 |
- /*******************************************************************************
- r.horizon: This module does one of two things:
- 1) Using a map of the terrain elevation it calculates for a set of points
- the angle height of the horizon for each point, using an angle interval given
- by the user.
- 2) For a given minimum angle it calculates one or more raster map giving the mazimum
- distance to a point on the horizon.
- This program was written in 2006 by Thomas Huld and Tomas Cebecauer,
- Joint Research Centre of the European Commission, based on bits of the r.sun module by Jaro Hofierka
- *******************************************************************************/
- /*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
- #include <grass/gis.h>
- #include <grass/raster.h>
- #include <grass/gprojects.h>
- #include <grass/glocale.h>
- #define WHOLE_RASTER 1
- #define SINGLE_POINT 0
- #define RAD (180. / M_PI)
- #define DEG ((M_PI)/180.)
- #define EARTHRADIUS 6371000.
- #define UNDEF 0. /* undefined value for terrain aspect */
- #define UNDEFZ -9999. /* undefined value for elevation */
- #define BIG 1.e20
- #define SMALL 1.e-20
- #define EPS 1.e-4
- #define DIST "1.0"
- #define DEGREEINMETERS 111120. /* 1852m/nm * 60nm/degree = 111120 m/deg */
- #define TANMINANGLE 0.008727 /* tan of minimum horizon angle (0.5 deg) */
- #define AMAX1(arg1, arg2) ((arg1) >= (arg2) ? (arg1) : (arg2))
- #define DISTANCE1(x1, x2, y1, y2) (sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2)))
- FILE *fp;
- const double pihalf = M_PI * 0.5;
- const double twopi = M_PI * 2.;
- const double invEarth = 1. / EARTHRADIUS;
- const double deg2rad = M_PI / 180.;
- const double rad2deg = 180. / M_PI;
- const double minAngle = DEG;
- const char *elevin;
- const char *horizon = NULL;
- const char *mapset = NULL;
- const char *per;
- char *shad_filename;
- char *outfile;
- struct Cell_head cellhd;
- struct Key_value *in_proj_info, *in_unit_info;
- struct pj_info iproj;
- struct pj_info oproj;
- struct Cell_head new_cellhd;
- double bufferZone = 0., ebufferZone = 0., wbufferZone = 0.,
- nbufferZone = 0., sbufferZone = 0.;
- int INPUT(void);
- int OUTGR(int numrows, int numcols);
- double amax1(double, double);
- double amin1(double, double);
- int min(int, int);
- int max(int, int);
- void com_par(double angle);
- int is_shadow(void);
- double horizon_height(void);
- void calculate_shadow();
- double calculate_shadow_onedirection(double shadow_angle);
- int new_point();
- double searching();
- int test_low_res();
- /*void where_is_point();
- void cube(int, int);
- */
- void calculate(double xcoord, double ycoord, int buffer_e, int buffer_w,
- int buffer_s, int buffer_n);
- int ip, jp, ip100, jp100;
- int n, m, m100, n100;
- int degreeOutput, compassOutput = FALSE;
- float **z, **z100, **horizon_raster;
- double stepx, stepy, stepxhalf, stepyhalf, stepxy, xp, yp, op, dp, xg0, xx0,
- yg0, yy0, deltx, delty;
- double invstepx, invstepy, distxy;
- double offsetx, offsety;
- double single_direction;
- /*int arrayNumInt; */
- double xmin, xmax, ymin, ymax, zmax = 0.;
- int d, day, tien = 0;
- double length, maxlength = BIG, zmult = 1.0, dist;
- double fixedMaxLength = BIG, step = 0.0, start = 0.0, end = 0.0;
- char *tt, *lt;
- double z_orig, zp;
- double h0, tanh0, angle;
- double stepsinangle, stepcosangle, sinangle, cosangle, distsinangle,
- distcosangle;
- double TOLER;
- const char *str_step;
- int mode;
- int isMode()
- {
- return mode;
- }
- void setMode(int val)
- {
- mode = val;
- }
- int ll_correction = FALSE;
- double coslatsq;
- /* why not use G_distance() here which switches to geodesic/great
- circle distance as needed? */
- double distance(double x1, double x2, double y1, double y2)
- {
- if (ll_correction) {
- return DEGREEINMETERS * sqrt(coslatsq * (x1 - x2) * (x1 - x2)
- + (y1 - y2) * (y1 - y2));
- }
- else {
- return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
- }
- }
- int main(int argc, char *argv[])
- {
- double xcoord, ycoord;
- struct GModule *module;
- struct
- {
- struct Option *elevin, *dist, *coord, *direction, *horizon,
- *step, *start, *end, *bufferzone, *e_buff, *w_buff,
- *n_buff, *s_buff, *maxdistance, *output;
- } parm;
- struct
- {
- struct Flag *degreeOutput, *compassOutput;
- }
- flag;
- G_gisinit(argv[0]);
- module = G_define_module();
- G_add_keyword(_("raster"));
- G_add_keyword(_("solar"));
- G_add_keyword(_("sun position"));
- module->label =
- _("Computes horizon angle height from a digital elevation model.");
- module->description =
- _("The module has two "
- "different modes of operation: "
- "1. Computes the entire horizon around a single point whose coordinates are "
- "given with the 'coord' option. The horizon height (in radians). "
- "2. Computes one or more raster maps of the horizon height in a single direction. "
- "The input for this is the angle (in degrees), which is measured "
- "counterclockwise with east=0, north=90 etc. The output is the horizon height in radians.");
- parm.elevin = G_define_standard_option(G_OPT_R_ELEV);
- parm.elevin->guisection = _("Input");
- parm.direction = G_define_option();
- parm.direction->key = "direction";
- parm.direction->type = TYPE_DOUBLE;
- parm.direction->required = NO;
- parm.direction->description =
- _("Direction in which you want to know the horizon height");
- parm.direction->guisection = _("Input");
- parm.step = G_define_option();
- parm.step->key = "step";
- parm.step->type = TYPE_DOUBLE;
- parm.step->required = NO;
- parm.step->description =
- _("Angle step size for multidirectional horizon [degrees]");
- parm.step->guisection = _("Input");
- parm.start = G_define_option();
- parm.start->key = "start";
- parm.start->type = TYPE_DOUBLE;
- parm.start->answer = "0.0";
- parm.start->required = NO;
- parm.start->description =
- _("Start angle for multidirectional horizon [degrees]");
- parm.start->guisection = _("Raster mode");
- parm.end = G_define_option();
- parm.end->key = "end";
- parm.end->type = TYPE_DOUBLE;
- parm.end->answer = "360.0";
- parm.end->required = NO;
- parm.end->description =
- _("End angle for multidirectional horizon [degrees]");
- parm.end->guisection = _("Raster mode");
- parm.bufferzone = G_define_option();
- parm.bufferzone->key = "bufferzone";
- parm.bufferzone->type = TYPE_DOUBLE;
- parm.bufferzone->required = NO;
- parm.bufferzone->description =
- _("For horizon rasters, read from the DEM an extra buffer around the present region");
- parm.bufferzone->guisection = _("Raster mode");
- parm.e_buff = G_define_option();
- parm.e_buff->key = "e_buff";
- parm.e_buff->type = TYPE_DOUBLE;
- parm.e_buff->required = NO;
- parm.e_buff->description =
- _("For horizon rasters, read from the DEM an extra buffer eastward the present region");
- parm.e_buff->guisection = _("Raster mode");
- parm.w_buff = G_define_option();
- parm.w_buff->key = "w_buff";
- parm.w_buff->type = TYPE_DOUBLE;
- parm.w_buff->required = NO;
- parm.w_buff->description =
- _("For horizon rasters, read from the DEM an extra buffer westward the present region");
- parm.w_buff->guisection = _("Raster mode");
- parm.n_buff = G_define_option();
- parm.n_buff->key = "n_buff";
- parm.n_buff->type = TYPE_DOUBLE;
- parm.n_buff->required = NO;
- parm.n_buff->description =
- _("For horizon rasters, read from the DEM an extra buffer northward the present region");
- parm.n_buff->guisection = _("Raster mode");
- parm.s_buff = G_define_option();
- parm.s_buff->key = "s_buff";
- parm.s_buff->type = TYPE_DOUBLE;
- parm.s_buff->required = NO;
- parm.s_buff->description =
- _("For horizon rasters, read from the DEM an extra buffer southward the present region");
- parm.s_buff->guisection = _("Raster mode");
- parm.maxdistance = G_define_option();
- parm.maxdistance->key = "maxdistance";
- parm.maxdistance->type = TYPE_DOUBLE;
- parm.maxdistance->required = NO;
- parm.maxdistance->description =
- _("The maximum distance to consider when finding the horizon height");
- parm.maxdistance->guisection = _("Optional");
- parm.horizon = G_define_standard_option(G_OPT_R_BASENAME_OUTPUT);
- parm.horizon->required = NO;
- parm.horizon->guisection = _("Raster mode");
- parm.coord = G_define_standard_option(G_OPT_M_COORDS);
- parm.coord->description =
- _("Coordinate for which you want to calculate the horizon");
- parm.coord->guisection = _("Point mode");
- parm.dist = G_define_option();
- parm.dist->key = "distance";
- parm.dist->type = TYPE_DOUBLE;
- parm.dist->answer = DIST;
- parm.dist->required = NO;
- parm.dist->description = _("Sampling distance step coefficient (0.5-1.5)");
- parm.dist->guisection = _("Optional");
- parm.output = G_define_standard_option(G_OPT_F_OUTPUT);
- parm.output->key = "file";
- parm.output->required = NO;
- parm.output->answer = "-";
- parm.output->description =
- _("Name of file for output (use output=- for stdout)");
- parm.output->guisection = _("Point mode");
- flag.degreeOutput = G_define_flag();
- flag.degreeOutput->key = 'd';
- flag.degreeOutput->description =
- _("Write output in degrees (default is radians)");
- flag.compassOutput = G_define_flag();
- flag.compassOutput->key = 'c';
- flag.compassOutput->description =
- _("Write output in compass orientation (default is CCW, East=0)");
- if (G_parser(argc, argv))
- exit(EXIT_FAILURE);
- G_get_set_window(&cellhd);
- stepx = cellhd.ew_res;
- stepy = cellhd.ns_res;
- stepxhalf = stepx / 2.;
- stepyhalf = stepy / 2.;
- invstepx = 1. / stepx;
- invstepy = 1. / stepy;
- /*
- offsetx = 2. * invstepx;
- offsety = 2. * invstepy;
- offsetx = 0.5*stepx;
- offsety = 0.5*stepy;
- */
- offsetx = 0.5;
- offsety = 0.5;
- n /*n_cols */ = cellhd.cols;
- m /*n_rows */ = cellhd.rows;
- n100 = ceil(n / 100.);
- m100 = ceil(m / 100.);
- xmin = cellhd.west;
- ymin = cellhd.south;
- xmax = cellhd.east;
- ymax = cellhd.north;
- deltx = fabs(cellhd.east - cellhd.west);
- delty = fabs(cellhd.north - cellhd.south);
- degreeOutput = flag.degreeOutput->answer;
- compassOutput = flag.compassOutput->answer;
- if (G_projection() == PROJECTION_LL)
- G_important_message(_("Note: In latitude-longitude coordinate system specify buffers in degree unit"));
- elevin = parm.elevin->answer;
- if (parm.coord->answer == NULL) {
- G_debug(1, "Setting mode: WHOLE_RASTER");
- setMode(WHOLE_RASTER);
- }
- else {
- G_debug(1, "Setting mode: SINGLE_POINT");
- setMode(SINGLE_POINT);
- if (sscanf(parm.coord->answer, "%lf,%lf", &xcoord, &ycoord) != 2) {
- G_fatal_error(
- _("Can't read the coordinates from the \"coordinate\" option."));
- }
- /* Transform the coordinates to row/column */
- /*
- xcoord = (int) ((xcoord-xmin)/stepx);
- ycoord = (int) ((ycoord-ymin)/stepy);
- */
-
- /* Open ASCII file for output or stdout */
- outfile = parm.output->answer;
- if ((strcmp("-", outfile)) == 0) {
- fp = stdout;
- }
- else if (NULL == (fp = fopen(outfile, "w")))
- G_fatal_error(_("Unable to open file <%s>"), outfile);
- }
- if (parm.direction->answer != NULL)
- sscanf(parm.direction->answer, "%lf", &single_direction);
- if (isMode(WHOLE_RASTER)) {
- if ((parm.direction->answer == NULL) && (parm.step->answer == NULL)) {
- G_fatal_error(
- _("You didn't specify a direction value or step size. Aborting."));
- }
- if (parm.horizon->answer == NULL) {
- G_fatal_error(
- _("You didn't specify a horizon raster name. Aborting."));
- }
- horizon = parm.horizon->answer;
- if (parm.step->answer != NULL) {
- str_step = parm.step->answer;
- sscanf(parm.step->answer, "%lf", &step);
- }
- else {
- step = 0;
- str_step = "0";
- }
- sscanf(parm.start->answer, "%lf", &start);
- sscanf(parm.end->answer, "%lf", &end);
- if (start < 0.0) {
- G_fatal_error(
- _("Negative values of start angle are not allowed. Aborting."));
- }
- if (end < 0.0 || end > 360.0) {
- G_fatal_error(
- _("End angle is not between 0 and 360. Aborting."));
- }
- if (start >= end) {
- G_fatal_error(
- _("You specify a start grater than the end angle. Aborting."));
- }
- G_debug(1, "Angle step: %g, start: %g, end: %g", step, start, end);
- }
- else {
- if (parm.step->answer == NULL) {
- G_fatal_error(
- _("You didn't specify an angle step size. Aborting."));
- }
- sscanf(parm.step->answer, "%lf", &step);
- }
- if (step == 0.0) {
- step = 360.;
- }
- if (parm.bufferzone->answer != NULL) {
- if (sscanf(parm.bufferzone->answer, "%lf", &bufferZone) != 1)
- G_fatal_error(_("Could not read bufferzone size. Aborting."));
- }
- if (parm.e_buff->answer != NULL) {
- if (sscanf(parm.e_buff->answer, "%lf", &ebufferZone) != 1)
- G_fatal_error(_("Could not read %s bufferzone size. Aborting."),
- _("east"));
- }
- if (parm.w_buff->answer != NULL) {
- if (sscanf(parm.w_buff->answer, "%lf", &wbufferZone) != 1)
- G_fatal_error(_("Could not read %s bufferzone size. Aborting."),
- _("west"));
- }
- if (parm.s_buff->answer != NULL) {
- if (sscanf(parm.s_buff->answer, "%lf", &sbufferZone) != 1)
- G_fatal_error(
- _("Could not read %s bufferzone size. Aborting."),
- _("south"));
- }
- if (parm.n_buff->answer != NULL) {
- if (sscanf(parm.n_buff->answer, "%lf", &nbufferZone) != 1)
- G_fatal_error(
- _("Could not read %s bufferzone size. Aborting."),
- _("north"));
- }
- if (parm.maxdistance->answer != NULL) {
- if (sscanf(parm.maxdistance->answer, "%lf", &fixedMaxLength) != 1)
- G_fatal_error(_("Could not read maximum distance. Aborting."));
- }
- G_debug(1,"Using maxdistance %f", fixedMaxLength); /* predefined as BIG */
- /* TODO: fixing BIG, there is a bug with distant mountains not being seen: attempt to contrain to current region
-
- fixedMaxLength = (fixedMaxLength < AMAX1(deltx, delty)) ? fixedMaxLength : AMAX1(deltx, delty);
- G_debug(1,"Using maxdistance %f", fixedMaxLength);
- */
- sscanf(parm.dist->answer, "%lf", &dist);
- if (dist < 0.5 || dist > 1.5 ) G_fatal_error(_("The distance value must be 0.5-1.5. Aborting."));
- stepxy = dist * 0.5 * (stepx + stepy);
- distxy = dist;
- TOLER = stepxy * EPS;
- if (bufferZone > 0. || ebufferZone > 0. || wbufferZone > 0. ||
- sbufferZone > 0. || nbufferZone > 0.) {
- new_cellhd = cellhd;
- if (ebufferZone == 0.)
- ebufferZone = bufferZone;
- if (wbufferZone == 0.)
- wbufferZone = bufferZone;
- if (sbufferZone == 0.)
- sbufferZone = bufferZone;
- if (nbufferZone == 0.)
- nbufferZone = bufferZone;
- new_cellhd.rows += (int)((nbufferZone + sbufferZone) / stepy);
- new_cellhd.cols += (int)((ebufferZone + wbufferZone) / stepx);
- new_cellhd.north += nbufferZone;
- new_cellhd.south -= sbufferZone;
- new_cellhd.east += ebufferZone;
- new_cellhd.west -= wbufferZone;
- xmin = new_cellhd.west;
- ymin = new_cellhd.south;
- xmax = new_cellhd.east;
- ymax = new_cellhd.north;
- deltx = fabs(new_cellhd.east - new_cellhd.west);
- delty = fabs(new_cellhd.north - new_cellhd.south);
- n /* n_cols */ = new_cellhd.cols;
- m /* n_rows */ = new_cellhd.rows;
- G_debug(1,"%lf %lf %lf %lf \n",ymax, ymin, xmin,xmax);
- n100 = ceil(n / 100.);
- m100 = ceil(m / 100.);
- Rast_set_window(&new_cellhd);
- }
- struct Key_Value *in_proj_info, *in_unit_info;
- if ((in_proj_info = G_get_projinfo()) == NULL)
- G_fatal_error(
- _("Can't get projection info of current location"));
- if ((in_unit_info = G_get_projunits()) == NULL)
- G_fatal_error(_("Can't get projection units of current location"));
- if (pj_get_kv(&iproj, in_proj_info, in_unit_info) < 0)
- G_fatal_error(
- _("Can't get projection key values of current location"));
- G_free_key_value(in_proj_info);
- G_free_key_value(in_unit_info);
- /* Set output projection to latlong w/ same ellipsoid */
- oproj.zone = 0;
- oproj.meters = 1.;
- sprintf(oproj.proj, "ll");
- if ((oproj.pj = pj_latlong_from_proj(iproj.pj)) == NULL)
- G_fatal_error(_("Unable to set up lat/long projection parameters"));
- /**********end of parser - ******************************/
- INPUT();
- G_debug(1, "calculate() starts...");
- calculate(xcoord, ycoord, (int)(ebufferZone / stepx),
- (int)(wbufferZone / stepx), (int)(sbufferZone / stepy),
- (int)(nbufferZone / stepy));
- exit(EXIT_SUCCESS);
- }
- /**********************end of main.c*****************/
- int INPUT(void)
- {
- FCELL *cell1;
- int fd1, row, row_rev;
- int l, i, j, k;
- int lmax, kmax;
- cell1 = Rast_allocate_f_buf();
- z = (float **)G_malloc(sizeof(float *) * (m));
- z100 = (float **)G_malloc(sizeof(float *) * (m100));
- for (l = 0; l < m; l++) {
- z[l] = (float *)G_malloc(sizeof(float) * (n));
- }
- for (l = 0; l < m100; l++) {
- z100[l] = (float *)G_malloc(sizeof(float) * (n100));
- }
- /*read Z raster */
- fd1 = Rast_open_old(elevin, "");
- for (row = 0; row < m; row++) {
- Rast_get_f_row(fd1, cell1, row);
- for (j = 0; j < n; j++) {
- row_rev = m - row - 1;
- if (!Rast_is_f_null_value(cell1 + j))
- z[row_rev][j] = (float)cell1[j];
- else
- z[row_rev][j] = UNDEFZ;
- }
- }
- Rast_close(fd1);
- /* create low resolution array 100 */
- for (i = 0; i < m100; i++) {
- lmax = (i + 1) * 100;
- if (lmax > m)
- lmax = m;
- for (j = 0; j < n100; j++) {
- zmax = SMALL;
- kmax = (j + 1) * 100;
- if (kmax > n)
- kmax = n;
- for (l = (i * 100); l < lmax; l++) {
- for (k = (j * 100); k < kmax; k++) {
- zmax = amax1(zmax, z[l][k]);
- }
- }
- z100[i][j] = zmax;
- G_debug(3,"%d %d %lf\n", i, j, z100[i][j]);
- }
- }
- /* find max Z */
- for (i = 0; i < m; i++) {
- for (j = 0; j < n; j++) {
- zmax = amax1(zmax, z[i][j]);
- }
- }
- return 1;
- }
- int OUTGR(int numrows, int numcols)
- {
- FCELL *cell1 = NULL;
- int fd1 = 0;
- int i, iarc, j;
- Rast_set_window(&cellhd);
- if (horizon != NULL) {
- cell1 = Rast_allocate_f_buf();
- fd1 = Rast_open_fp_new(shad_filename);
- }
- if (numrows != Rast_window_rows())
- G_fatal_error(_("OOPS: rows changed from %d to %d"), numrows,
- Rast_window_rows());
- if (numcols != Rast_window_cols())
- G_fatal_error(_("OOPS: cols changed from %d to %d"), numcols,
- Rast_window_cols());
- for (iarc = 0; iarc < numrows; iarc++) {
- i = numrows - iarc - 1;
- if (horizon != NULL) {
- for (j = 0; j < numcols; j++) {
- if (horizon_raster[i][j] == UNDEFZ)
- Rast_set_f_null_value(cell1 + j, 1);
- else
- cell1[j] = (FCELL) horizon_raster[i][j];
- }
- Rast_put_f_row(fd1, cell1);
- }
- } /* End loop over rows. */
- Rast_close(fd1);
- return 1;
- }
- double amax1(arg1, arg2)
- double arg1;
- double arg2;
- {
- double res;
- if (arg1 >= arg2) {
- res = arg1;
- }
- else {
- res = arg2;
- }
- return res;
- }
- double amin1(arg1, arg2)
- double arg1;
- double arg2;
- {
- double res;
- if (arg1 <= arg2) {
- res = arg1;
- }
- else {
- res = arg2;
- }
- return res;
- }
- int min(arg1, arg2)
- int arg1;
- int arg2;
- {
- int res;
- if (arg1 <= arg2) {
- res = arg1;
- }
- else {
- res = arg2;
- }
- return res;
- }
- int max(arg1, arg2)
- int arg1;
- int arg2;
- {
- int res;
- if (arg1 >= arg2) {
- res = arg1;
- }
- else {
- res = arg2;
- }
- return res;
- }
- /**********************************************************/
- void com_par(double angle)
- {
- sinangle = sin(angle);
- if (fabs(sinangle) < 0.0000001) {
- sinangle = 0.;
- }
- cosangle = cos(angle);
- if (fabs(cosangle) < 0.0000001) {
- cosangle = 0.;
- }
- distsinangle = 32000;
- distcosangle = 32000;
- if (sinangle != 0.) {
- distsinangle = 100. / (distxy * sinangle);
- }
- if (cosangle != 0.) {
- distcosangle = 100. / (distxy * cosangle);
- }
- stepsinangle = stepxy * sinangle;
- stepcosangle = stepxy * cosangle;
- }
- double horizon_height(void)
- {
- double height;
- tanh0 = 0.;
- length = 0;
- height = searching();
- xx0 = xg0;
- yy0 = yg0;
- return height;
- }
- double calculate_shadow_onedirection(double shadow_angle)
- {
- shadow_angle = horizon_height();
- return shadow_angle;
- }
- void calculate_shadow()
- {
- double dfr_rad;
- int i;
- int printCount;
- double shadow_angle;
- double printangle;
- double sx, sy;
- double xp, yp;
- double latitude, longitude;
- double delt_lat, delt_lon;
- double delt_east, delt_nor;
- double delt_dist;
- double angle;
- printCount = 360. / fabs(step);
- if (printCount < 1)
- printCount = 1;
- dfr_rad = step * deg2rad;
- xp = xmin + xx0;
- yp = ymin + yy0;
- angle = (single_direction * deg2rad) + pihalf;
- maxlength = fixedMaxLength;
- fprintf(fp, "azimuth,horizon_height\n");
- for (i = 0; i < printCount; i++) {
- ip = jp = 0;
- sx = xx0 * invstepx;
- sy = yy0 * invstepy;
- ip100 = floor(sx / 100.);
- jp100 = floor(sy / 100.);
- if ((G_projection() != PROJECTION_LL)) {
- longitude = xp;
- latitude = yp;
- if (pj_do_proj(&longitude, &latitude, &iproj, &oproj) < 0) {
- G_fatal_error(_("Error in pj_do_proj"));
- }
- }
- else { /* ll projection */
- latitude = yp;
- longitude = xp;
- }
- latitude *= deg2rad;
- longitude *= deg2rad;
- delt_lat = -0.0001 * cos(angle);
- delt_lon = 0.0001 * sin(angle) / cos(latitude);
- latitude = (latitude + delt_lat) * rad2deg;
- longitude = (longitude + delt_lon) * rad2deg;
- if (pj_do_proj(&longitude, &latitude, &oproj, &iproj) < 0) {
- G_fatal_error(_("Error in pj_do_proj"));
- }
- delt_east = longitude - xp;
- delt_nor = latitude - yp;
- delt_dist = sqrt(delt_east * delt_east + delt_nor * delt_nor);
- stepsinangle = stepxy * delt_nor / delt_dist;
- stepcosangle = stepxy * delt_east / delt_dist;
- shadow_angle = horizon_height();
- if (degreeOutput) {
- shadow_angle *= rad2deg;
- }
- printangle = angle * rad2deg - 90.;
- if (printangle < 0.)
- printangle += 360;
- else if (printangle >= 360.)
- printangle -= 360;
- if(compassOutput ){
- double tmpangle;
-
- tmpangle = 360. - printangle + 90.;
- if (tmpangle >= 360.)
- tmpangle = tmpangle - 360.;
- fprintf(fp, "%lf,%lf\n", tmpangle, shadow_angle);
- } else {
- fprintf(fp, "%lf,%lf\n", printangle, shadow_angle);
- }
- angle += dfr_rad;
- if (angle < 0.)
- angle += twopi;
- else if (angle > twopi)
- angle -= twopi;
- } /* end of for loop over angles */
- }
- /*////////////////////////////////////////////////////////////////////// */
- int new_point()
- {
- int iold, jold;
- int succes = 1, succes2 = 1;
- double sx, sy;
- double dx, dy;
- iold = ip;
- jold = jp;
- while (succes) {
- yy0 += stepsinangle;
- xx0 += stepcosangle;
- /* offset 0.5 cell size to get the right cell i, j */
- sx = xx0 * invstepx + offsetx;
- sy = yy0 * invstepy + offsety;
- ip = (int)sx;
- jp = (int)sy;
- /* test outside of raster */
- if ((ip < 0) || (ip >= n) || (jp < 0) || (jp >= m))
- return (3);
- if ((ip != iold) || (jp != jold)) {
- dx = (double)ip *stepx;
- dy = (double)jp *stepy;
- length = distance(xg0, dx, yg0, dy); /* dist from orig. grid point to the current grid point */
- succes2 = test_low_res();
- if (succes2 == 1) {
- zp = z[jp][ip];
- return (1);
- }
- }
- }
- return -1;
- }
- int test_low_res()
- {
- int iold100, jold100;
- double sx, sy;
- int delx, dely, mindel;
- double zp100, z2, curvature_diff;
- iold100 = ip100;
- jold100 = jp100;
- ip100 = floor(ip / 100.);
- jp100 = floor(jp / 100.);
- /*test the new position with low resolution */
- if ((ip100 != iold100) || (jp100 != jold100)) {
- G_debug(2,"ip:%d jp:%d iold100:%d jold100:%d\n",ip,jp, iold100,jold100);
- /* replace with approximate version
- curvature_diff = EARTHRADIUS*(1.-cos(length/EARTHRADIUS));
- */
- curvature_diff = 0.5 * length * length * invEarth;
- z2 = z_orig + curvature_diff + length * tanh0;
- zp100 = z100[jp100][ip100];
- G_debug(2,"ip:%d jp:%d z2:%lf zp100:%lf \n",ip,jp,z2,zp100);
- if (zp100 <= z2)
- /*skip to the next lowres cell */
- {
- delx = 32000;
- dely = 32000;
- if (cosangle > 0.) {
- sx = xx0 * invstepx + offsetx;
- delx =
- floor(fabs
- ((ceil(sx / 100.) - (sx / 100.)) * distcosangle));
- }
- if (cosangle < 0.) {
- sx = xx0 * invstepx + offsetx;
- delx =
- floor(fabs
- ((floor(sx / 100.) - (sx / 100.)) * distcosangle));
- }
- if (sinangle > 0.) {
- sy = yy0 * invstepy + offsety;
- dely =
- floor(fabs
- ((ceil(sy / 100.) - (sy / 100.)) * distsinangle));
- }
- else if (sinangle < 0.) {
- sy = yy0 * invstepy + offsety;
- dely =
- floor(fabs
- ((floor(jp / 100.) - (sy / 100.)) * distsinangle));
- }
- mindel = min(delx, dely);
- G_debug(2,"%d %d %d %lf %lf\n",ip, jp, mindel,xg0, yg0);
- yy0 = yy0 + (mindel * stepsinangle);
- xx0 = xx0 + (mindel * stepcosangle);
- G_debug(2," %lf %lf\n",xx0,yy0);
- return (3);
- }
- else {
- return (1); /* change of low res array - new cell is reaching limit for high resolution processing */
- }
- }
- else {
- return (1); /* no change of low res array */
- }
- }
- double searching()
- {
- double z2;
- double curvature_diff;
- int succes = 1;
- if (zp == UNDEFZ)
- return 0;
- while (1) {
- succes = new_point();
- if (succes != 1) {
- break;
- }
- /* curvature_diff = EARTHRADIUS*(1.-cos(length/EARTHRADIUS)); */
- curvature_diff = 0.5 * length * length * invEarth;
- z2 = z_orig + curvature_diff + length * tanh0;
- if (z2 < zp) {
- tanh0 = (zp - z_orig - curvature_diff) / length;
- }
- if (z2 >= zmax) {
- break;
- }
- if (length >= maxlength) {
- break;
- }
- }
- return atan(tanh0);
- }
- /*////////////////////////////////////////////////////////////////////// */
- void calculate(double xcoord, double ycoord, int buffer_e, int buffer_w,
- int buffer_s, int buffer_n)
- {
- int i, j, l, k = 0;
- size_t decimals;
- int xindex, yindex;
- double shadow_angle;
- double coslat;
- double latitude, longitude;
- double xp, yp;
- double inputAngle;
- double delt_lat, delt_lon;
- double delt_east, delt_nor;
- double delt_dist;
- char msg_buff[256];
- int hor_row_start = buffer_s;
- int hor_row_end = m - buffer_n;
- int hor_col_start = buffer_w;
- int hor_col_end = n - buffer_e;
- int hor_numrows = m - (buffer_s + buffer_n);
- int hor_numcols = n - (buffer_e + buffer_w);
- int arrayNumInt;
- double dfr_rad, angle_deg;
- xindex = (int)((xcoord - xmin) / stepx);
- yindex = (int)((ycoord - ymin) / stepy);
- if ((G_projection() == PROJECTION_LL)) {
- ll_correction = TRUE;
- }
- if (isMode() == SINGLE_POINT) {
- /* Calculate the horizon for one single point */
- /*
- xg0 = xx0 = (double)xcoord * stepx;
- yg0 = yy0 = (double)ycoord * stepy;
- xg0 = xx0 = xcoord -0.5*stepx -xmin;
- yg0 = yy0 = ycoord -0.5*stepy-ymin;
- xg0 = xx0 = xindex*stepx -0.5*stepx;
- yg0 = yy0 = yindex*stepy -0.5*stepy;
- */
- xg0 = xx0 = xindex * stepx;
- yg0 = yy0 = yindex * stepy;
- if (ll_correction) {
- coslat = cos(deg2rad * (ymin + yy0));
- coslatsq = coslat * coslat;
- }
- z_orig = zp = z[yindex][xindex];
- G_debug(1, "yindex: %d, xindex %d, z_orig %.2f", yindex, xindex, z_orig);
- calculate_shadow();
- fclose(fp);
- }
- else {
- /****************************************************************/
- /* The loop over raster points starts here! */
- /****************************************************************/
- if (horizon != NULL) {
- horizon_raster = (float **)G_malloc(sizeof(float *) * (hor_numrows));
- for (l = 0; l < hor_numrows; l++) {
- horizon_raster[l] =
- (float *)G_malloc(sizeof(float) * (hor_numcols));
- }
- for (j = 0; j < hor_numrows; j++) {
- for (i = 0; i < hor_numcols; i++)
- horizon_raster[j][i] = 0.;
- }
- }
- /* definition of horizon angle in loop */
- if (step == 0.0) {
- dfr_rad = 0;
- arrayNumInt = 1;
- sprintf(shad_filename, "%s", horizon);
- }
- else {
- dfr_rad = step * deg2rad;
- arrayNumInt = (int)((end - start) / fabs(step));
- }
- decimals = G_get_num_decimals(str_step);
- for (k = 0; k < arrayNumInt; k++) {
- struct History history;
- angle = (start + single_direction) * deg2rad + (dfr_rad * k);
- angle_deg = angle * rad2deg + 0.0001;
- if (step != 0.0)
- shad_filename = G_generate_basename(horizon, angle_deg, 3, decimals);
- /*
- com_par(angle);
- */
- G_message(_("Calculating map %01d of %01d (angle %.2f, raster map <%s>)"),
- (k + 1), arrayNumInt, angle_deg, shad_filename);
- for (j = hor_row_start; j < hor_row_end; j++) {
- G_percent(j - hor_row_start, hor_numrows - 1, 2);
- shadow_angle = 15 * deg2rad;
- for (i = hor_col_start; i < hor_col_end; i++) {
- ip100 = floor(i / 100.);
- jp100 = floor(j / 100.);
- ip = jp = 0;
- xg0 = xx0 = (double)i *stepx;
- xp = xmin + xx0;
- yg0 = yy0 = (double)j *stepy;
- yp = ymin + yy0;
- length = 0;
- if (ll_correction) {
- coslat = cos(deg2rad * yp);
- coslatsq = coslat * coslat;
- }
- longitude = xp;
- latitude = yp;
- if ((G_projection() != PROJECTION_LL)) {
- if (pj_do_proj(&longitude, &latitude, &iproj, &oproj) < 0)
- G_fatal_error("Error in pj_do_proj");
- }
- latitude *= deg2rad;
- longitude *= deg2rad;
- inputAngle = angle + pihalf;
- inputAngle =
- (inputAngle >=
- twopi) ? inputAngle - twopi : inputAngle;
- delt_lat = -0.0001 * cos(inputAngle); /* Arbitrary small distance in latitude */
- delt_lon = 0.0001 * sin(inputAngle) / cos(latitude);
- latitude = (latitude + delt_lat) * rad2deg;
- longitude = (longitude + delt_lon) * rad2deg;
- if ((G_projection() != PROJECTION_LL)) {
- if (pj_do_proj(&longitude, &latitude, &oproj, &iproj) < 0)
- G_fatal_error("Error in pj_do_proj");
- }
- delt_east = longitude - xp;
- delt_nor = latitude - yp;
- delt_dist =
- sqrt(delt_east * delt_east + delt_nor * delt_nor);
- sinangle = delt_nor / delt_dist;
- if (fabs(sinangle) < 0.0000001) {
- sinangle = 0.;
- }
- cosangle = delt_east / delt_dist;
- if (fabs(cosangle) < 0.0000001) {
- cosangle = 0.;
- }
- distsinangle = 32000;
- distcosangle = 32000;
- if (sinangle != 0.) {
- distsinangle = 100. / (distxy * sinangle);
- }
- if (cosangle != 0.) {
- distcosangle = 100. / (distxy * cosangle);
- }
- stepsinangle = stepxy * sinangle;
- stepcosangle = stepxy * cosangle;
- z_orig = zp = z[j][i];
- maxlength = (zmax - z_orig) / TANMINANGLE;
- maxlength =
- (maxlength < fixedMaxLength) ? maxlength : fixedMaxLength;
- if (z_orig != UNDEFZ) {
- G_debug(4,"**************new line %d %d\n", i, j);
- shadow_angle = horizon_height();
- if (degreeOutput) {
- shadow_angle *= rad2deg;
- }
- /*
- if((j==1400)&&(i==1400))
- {
- G_debug(1, "coordinates=%f,%f, raster no. %d, horizon=%f\n",
- xp, yp, k, shadow_angle);
- }
- */
- horizon_raster[j - buffer_s][i - buffer_w] =
- shadow_angle;
- } /* undefs */
- }
- }
- G_debug(1, "OUTGR() starts...");
- OUTGR(cellhd.rows, cellhd.cols);
- /* empty array */
- for (j = 0; j < hor_numrows; j++) {
- for (i = 0; i < hor_numcols; i++)
- horizon_raster[j][i] = 0.;
- }
- /* return back the buffered region */
- if (bufferZone > 0.)
- Rast_set_window(&new_cellhd);
- /* write metadata */
- Rast_short_history(shad_filename, "raster", &history);
- sprintf(msg_buff,
- "Angular height of terrain horizon, map %01d of %01d",
- (k + 1), arrayNumInt);
- Rast_put_cell_title(shad_filename, msg_buff);
- if (degreeOutput)
- Rast_write_units(shad_filename, "degrees");
- else
- Rast_write_units(shad_filename, "radians");
- Rast_command_history(&history);
- /* insert a blank line */
- Rast_append_history(&history, "");
- Rast_append_format_history(
- &history,
- "Horizon view from azimuth angle %.2f degrees CCW from East",
- angle * rad2deg);
- Rast_write_history(shad_filename, &history);
- G_free(shad_filename);
- }
- }
- }
|