1 ;;; PHOROS -- Photogrammetric Road Survey
2 ;;; Copyright (C) 2010, 2011 Bert Burgemeister
4 ;;; This program is free software; you can redistribute it and/or modify
5 ;;; it under the terms of the GNU General Public License as published by
6 ;;; the Free Software Foundation; either version 2 of the License, or
7 ;;; (at your option) any later version.
9 ;;; This program is distributed in the hope that it will be useful,
10 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ;;; GNU General Public License for more details.
14 ;;; You should have received a copy of the GNU General Public License along
15 ;;; with this program; if not, write to the Free Software Foundation, Inc.,
16 ;;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 (hunchentoot:define-easy-handler
(phoros.js
) ()
21 "Serve some Javascript."
22 (when (hunchentoot:session-value
'authenticated-p
)
25 (setf debug-info
(@ *open-layers
*console info
))
27 (defmacro inner-html-with-id
(id)
28 "innerHTML of element with id=\"id\"."
29 `(chain document
(get-element-by-id ,id
) inner-h-t-m-l
))
31 (defmacro value-with-id
(id)
32 "Value of element with id=\"id\"."
33 `(chain document
(get-element-by-id ,id
) value
))
35 (defmacro checkbox-status-with-id
(id)
36 "Whether checkbox with id=\"id\" is checked or not."
37 `(chain document
(get-element-by-id ,id
) checked
))
43 (:p
"User role. \"Read\" can't write or modify anything.
44 \"Write\" may write user points and delete their own
45 ones. \"Admin\" may write user points and delete points
47 :presentation-project-name
49 (:p
"Presentation project name."))
50 :presentation-project-emptiness
52 (:p
"This presentation project is empty. You can't do much
56 (:p
"Phoros version.")
57 (:p
"In a version string A.B.C, changes in A denote
58 incompatible changes in data (you can't access a database
59 set up by a different version of Phoros); changes in B mean
60 user-visible changes in feature set; changes in C denote
61 bug fixes and minor improvements."))
64 (:p
"Current action."))
65 :multiple-points-phoros-controls
67 (:p
"Try reading the text under mouse pointer."))
70 (:p
"Store user point with its attribute,
71 numeric-description, description, and auxiliary data into
75 (:p
"Delete current point."))
76 :download-user-points-button
78 (:p
"Download all user points as GeoJSON-fomatted text
79 file. Do this regularly if you don't want to lose your
80 work due to server crashes or major Phoros updates.")
81 (:p
"Points saved this way can be fed back into your
82 project using the command line interface (on server or on
83 any other host where the database is reachable)."))
87 (:p
"The standard ones, polygon, polyline, and solitary are
88 rendered as asterisk, square, and triangle
89 respectively. Anything else is rendered as an X."))
92 (:h3
"\"description\"")
93 (:p
"Optional textual description of user point."))
94 :point-numeric-description
96 (:h3
"\"numeric-description\"")
97 (:p
"Optional additional description of user point. It is
98 occasionally used to label representions of this
99 point in streetmap and in images.")
100 (:p
"If parts of it look like numbers, the leftmost such
101 part is automatically incremented during first click into
105 (:p
"Creation date of current user point. Will be updated
106 when you change this point."))
109 (:p
"Check this if the user point being created is to
110 include auxiliary data."))
113 (:p
"Select a set of auxiliary data, either by its distance
114 (in metres) from the current estimated position, or by
115 clicking its representation in streetmap."))
118 (:p
"Auxiliary data connected to this presentation project;
119 all the numeric values followed by all the text values if
123 (:p
"Creator of current user point. Will be updated when
124 you change this point."))
125 :remove-work-layers-button
127 (:p
"Discard the current, unstored user point or unselect
128 any selected user points. Zoom out all images. Keep
129 the rest of the workspace untouched."))
132 (:p
"View some info about Phoros."))
135 (:p
"Finish this session after storing current streetmap
136 zoom status and your cursor position.")
137 (:p
"Fresh login is required to continue."))
140 (:p
"Clicking into the streetmap fetches images which most
141 probably feature the clicked point.")
142 (:p
"TODO: This is not quite so. Currently images taken
143 from points nearest to the clicked one are displayed.")
144 (:p
"To pan the map, drag the mouse. To zoom, spin the
145 mouse wheel, or hold shift down whilst dragging a box, or
146 double-click (shift double-click for larger zoom steps) a
147 point of interest."))
150 (:p
"Clicking into an image sets or resets the active point
151 there. Once a feature is marked by active points in more
152 than one image, the estimated position is calculated.")
153 (:p
"To pan an image, drag the mouse. To zoom, spin the
154 mouse wheel, or hold shift down whilst dragging a box, or
155 double-click (shift double-click for larger zoom steps) a
156 point of interest."))
157 ol-Control-Pan-West-Item-Inactive
159 (:p
"Move viewport left."))
160 ol-Control-Pan-East-Item-Inactive
162 (:p
"Move viewport right."))
163 ol-Control-Pan-North-Item-Inactive
165 (:p
"Move viewport up."))
166 ol-Control-Pan-South-Item-Inactive
168 (:p
"Move viewport down."))
169 ol-Control-Zoom-In-Item-Inactive
172 ol-Control-Zoom-Out-Item-Inactive
175 streetmap-Zoom-To-Max-Extent-Item-Inactive
177 (:p
"Zoom to the extent of presentation project."))
178 ol-Control-Zoom-To-Max-Extent-Item-Inactive
180 (:p
"Zoom out completely, restoring the original view."))
181 :zoom-images-to-max-extent
183 (:p
"Zoom all images out completely, restoring the original
187 (:p
"Check this to automatically zoom into images once they
188 get an estimated position."))
191 (:p
"Check this to snap your current position onto a line
192 along points of auxiliary data, and to keep streetmap
193 centered around current position."))
196 (:p
"Decrease step size. Double-click to decrease harder."))
199 (:p
"Step size in metres. Click to increase; double-click
200 to increase harder."))
203 (:p
"Increase step size. Double-click to increase harder."))
206 (:p
"Move your position by one step on a line along points
207 of auxiliary data. Double-click to change direction."))
208 :image-layer-switcher
210 (:p
"Toggle display of image."))
213 (:p
"Time this image was taken."))
216 (:p
"Choose a background streetmap."))
219 (:p
"Toggle visibility of data layers."))
222 (:p
"Click to re-center streetmap, or drag the red
224 :streetmap-mouse-position
226 (:p
"Cursor position in geographic coordinates when cursor
230 (:p
"Hints on Phoros' displays and controls are shown here
231 while hovering over the respective elements."))))
233 (defun add-help-topic (topic element
)
234 "Add mouse events to DOM element that initiate display of a
237 (setf (@ element onmouseover
)
239 (lambda () (show-help x
)))
241 (setf (@ element onmouseout
) show-help
)))
243 (defun add-help-events ()
244 "Add mouse events to DOM elements that initiate display of a
247 (topic *help-topics
*)
248 (add-help-topic topic
(chain document
(get-element-by-id topic
)))
249 (dolist (element (chain document
(get-elements-by-class-name topic
)))
250 (add-help-topic topic element
))))
252 (defun show-help (&optional topic
)
253 "Put text on topic into help-display"
254 (setf (inner-html-with-id "help-display")
255 (let ((help-body (getprop *help-topics
* topic
)))
256 (if (undefined help-body
)
260 (defvar *click-control
*
264 (@ *open-layers
*control
)
272 (apply this arguments
))
273 (setf (@ this handler
)
274 (new (chain *open-layers
278 :click
(@ this trigger
)))))))))))
280 (defvar +unix-epoch
+ (lisp *unix-epoch
*)
281 "Seconds between Lisp epoch and UNIX epoch.")
283 (new (chain *open-layers
(*projection
"EPSG:4326"))))
284 (defvar +spherical-mercator
+
285 (new (chain *open-layers
(*projection
"EPSG:900913"))))
287 (defvar +user-name
+ (lisp (hunchentoot:session-value
'user-name
))
288 "User's (short) name.")
289 (defvar +user-role
+ (lisp (string-downcase (hunchentoot:session-value
291 "User's permissions.")
293 (defvar +presentation-project-bbox-text
+
294 (lisp (hunchentoot:session-value
'presentation-project-bbox
)))
296 (defvar +presentation-project-bounds
+
297 (chain (new (chain *open-layers
300 (or +presentation-project-bbox-text
+
301 "-180,-89,180,89"))))
302 (transform +geographic
+ +spherical-mercator
+))
303 "Bounding box of the entire presentation project.")
306 (lisp (hunchentoot:session-value
'aux-data-p
)))
308 (defvar *images
* (array) "Collection of the photos currently shown.")
310 (defvar *streetmap
* undefined
311 "The streetmap shown to the user.")
313 (defvar *point-attributes-select
* undefined
314 "The HTML element for selecting user point attributes.")
316 (defvar *aux-point-distance-select
* undefined
317 "The HTML element for selecting one of a few nearest
320 (defvar *global-position
* undefined
321 "Coordinates of the current estimated position")
323 (defvar *linestring-step-ratio
* 4
324 "Look for auxiliary points to include into linestring within
325 a radius of *linestring-step-ratio* multilied by multiplied by
328 (defvar *current-nearest-aux-point
*
329 (create attributes
(create aux-numeric undefined
331 "Attributes of currently selected point of auxiliary data.")
334 (defvar *bbox-strategy
* (@ *open-layers
*strategy
*bbox
*))
335 (setf (@ *bbox-strategy
* prototype ratio
) 1.5)
336 (setf (@ *bbox-strategy
* prototype res-factor
) 1.5)
338 (defvar *json-parser
* (new (chain *open-layers
*format
*json
*)))
340 (defvar *geojson-format
* (chain *open-layers
*format
*geo-j-s-o-n
))
341 (setf (@ *geojson-format
* prototype ignore-extra-dims
)
342 t
) ;doesn't handle height anyway
343 (setf (@ *geojson-format
* prototype external-projection
)
345 (setf (@ *geojson-format
* prototype internal-projection
)
349 (new (chain *open-layers
352 (create external-projection
+geographic
+
353 internal-projection
+spherical-mercator
+)))))
355 (defvar *http-protocol
* (chain *open-layers
*protocol
*http
*))
356 (setf (chain *http-protocol
* prototype format
) (new *geojson-format
*))
358 (defvar *pristine-images-p
* t
359 "T if none of the current images has been clicked into yet.")
361 (defvar *current-user-point
* undefined
362 "The currently selected user-point.")
364 (defun write-permission-p (&optional
(current-owner +user-name
+))
365 "Nil if current user can't edit stuff created by
366 current-owner or, without arguments, new stuff."
367 (or (equal +user-role
+ "admin")
368 (and (equal +user-role
+ "write")
369 (equal +user-name
+ current-owner
))))
372 "Anything necessary to deal with a photo."
373 (setf (getprop this
'map
)
374 (new ((getprop *open-layers
'*map
)
375 (create projection
+spherical-mercator
+
377 controls
(array (new (chain *open-layers
380 (setf (getprop this
'dummy
) false
) ;TODO why? (omitting splices map components directly into *image)
383 (setf (getprop *image
'prototype
'show-photo
)
385 (setf (getprop *image
'prototype
'draw-epipolar-line
)
387 (setf (getprop *image
'prototype
'draw-active-point
)
389 (setf (getprop *image
'prototype
'draw-estimated-positions
)
390 draw-estimated-positions
)
392 (defun photo-path (photo-parameters)
393 "Create from stuff found in photo-parameters a path for use in
395 (+ "/phoros/lib/photo/" (@ photo-parameters directory
) "/"
396 (@ photo-parameters filename
) "/"
397 (@ photo-parameters byte-position
) ".png"
398 "?mounting-angle=" (@ photo-parameters mounting-angle
)
399 "&bayer-pattern=" (@ photo-parameters bayer-pattern
)
400 "&color-raiser=" (@ photo-parameters color-raiser
)))
402 (defun has-layer-p (map layer-name
)
403 "False if map doesn't have a layer called layer-name."
404 (chain map
(get-layers-by-name layer-name
) length
))
406 (defun some-active-point-p ()
407 "False if no image in *images* has an Active Point."
409 for i across
*images
*
410 sum
(has-layer-p (getprop i
'map
) "Active Point")))
412 (defun remove-layer (map layer-name
)
413 "Destroy layer layer-name in map."
414 (when (has-layer-p map layer-name
)
415 (chain map
(get-layers-by-name layer-name
) 0 (destroy))))
417 (defun remove-any-layers (layer-name)
418 "Destroy in all *images* and in *streetmap* the layer named layer-name."
420 for i across
*images
* do
421 (remove-layer (getprop i
'map
) layer-name
))
422 (remove-layer *streetmap
* layer-name
))
424 (defun reset-controls ()
425 (reveal-element-with-id "real-phoros-controls")
426 (hide-element-with-id "multiple-points-phoros-controls")
427 (disable-element-with-id "finish-point-button")
428 (disable-element-with-id "delete-point-button")
429 (disable-element-with-id "remove-work-layers-button")
430 (setf (inner-html-with-id "h2-controls") "Create Point")
431 (setf (inner-html-with-id "creator") nil
)
432 (setf (inner-html-with-id "point-creation-date") nil
)
433 (hide-aux-data-choice)
434 (setf (inner-html-with-id "aux-numeric-list") nil
)
435 (setf (inner-html-with-id "aux-text-list") nil
))
437 (defun disable-streetmap-nearest-aux-points-layer ()
438 "Get (@ *streetmap* nearest-aux-points-layer) out of the way,
439 I.e., remove features and disable feature select control so it won't
440 shadow any other control."
441 (chain *streetmap
* nearest-aux-points-layer
(remove-all-features))
442 (chain *streetmap
* nearest-aux-points-select-control
(deactivate))
443 (chain *streetmap
* user-points-select-control
(activate)))
445 (defun reset-layers-and-controls ()
446 "Destroy user-generated layers in *streetmap* and in all
447 *images*, and put controls into pristine state."
448 (remove-any-layers "Epipolar Line")
449 (remove-any-layers "Active Point")
450 (remove-any-layers "Estimated Position")
451 (remove-any-layers "User Point")
452 (chain *streetmap
* user-points-select-control
(unselect-all))
453 (disable-streetmap-nearest-aux-points-layer)
454 (when (and (not (equal undefined
*current-user-point
*))
455 (@ *current-user-point
* layer
))
457 user-points-select-control
458 (unselect *current-user-point
*)))
460 (setf *pristine-images-p
* t
)
461 (zoom-images-to-max-extent))
463 (defun enable-element-with-id (id)
464 "Activate HTML element with id=\"id\"."
465 (setf (chain document
(get-element-by-id id
) disabled
) nil
))
467 (defun disable-element-with-id (id)
468 "Grey out HTML element with id=\"id\"."
469 (setf (chain document
(get-element-by-id id
) disabled
) t
))
471 (defun hide-element-with-id (id)
472 "Hide HTML element wit id=\"id\"."
473 (setf (chain document
(get-element-by-id id
) style display
)
476 (defun reveal-element-with-id (id)
477 "Reveal HTML element wit id=\"id\"."
478 (setf (chain document
(get-element-by-id id
) style display
)
481 (defun hide-aux-data-choice ()
482 "Disable selector for auxiliary data."
483 ;;(disable-element-with-id "include-aux-data-p")
484 (hide-element-with-id "include-aux-data")
485 (hide-element-with-id "aux-point-distance")
486 (setf (chain document
487 (get-element-by-id "aux-point-distance")
492 (defun refresh-layer (layer)
493 "Have layer re-request and redraw features."
494 (chain layer
(refresh (create :force t
))))
496 (defun present-photos ()
497 "Handle the response triggered by request-photos-for-point."
498 (let ((photo-parameters
501 photo-request-response response-text
)))))
503 for p across photo-parameters
504 for i across
*images
*
506 (setf (getprop i
'photo-parameters
) p
)
507 ((getprop i
'show-photo
)))
508 ;; (setf (@ (aref photo-parameters 0) angle180) 1) ; Debug: coordinate flipping
511 (defun consolidate-combobox (combobox-id)
512 "Help faking a combobox: copy selected option into input."
513 (let ((combobox-select (+ combobox-id
"-select"))
514 (combobox-input (+ combobox-id
"-input")))
515 (setf (value-with-id combobox-input
)
516 (getprop (chain document
517 (get-element-by-id combobox-select
)
520 (get-element-by-id combobox-select
)
524 (get-element-by-id combobox-input
)
527 (defun unselect-combobox-selection (combobox-id)
528 "Help faking a combobox: unset selected option so any
529 selection there will trigger an onchange event."
530 (let ((combobox-select (+ combobox-id
"-select")))
531 (setf (chain document
532 (get-element-by-id combobox-select
)
536 (defun stuff-combobox (combobox-id values
&optional selection
)
537 "Stuff combobox with values. If selection is a number,
538 select the respective item."
539 (let ((combobox-select (+ combobox-id
"-select"))
540 (combobox-input (+ combobox-id
"-input")))
541 (setf (chain document
542 (get-element-by-id combobox-select
)
546 (loop for i in values do
548 (chain document
(create-element "option")))
549 (setf (@ combobox-item text
) i
)
551 (get-element-by-id combobox-select
)
552 (add combobox-item null
)))
554 (setf (chain document
555 (get-element-by-id combobox-select
)
558 (consolidate-combobox combobox-id
))))
560 (defun stuff-user-point-comboboxes (&optional selectp
)
561 "Stuff user point attribute comboboxes with sensible values.
562 If selectp it t, select the most frequently used one."
566 user-point-choice-response response-text
))))
568 (chain response attributes
(map (lambda (x)
571 (chain response descriptions
(map (lambda (x)
572 (@ x description
)))))
574 best-used-description
)
578 for i across
(@ response descriptions
)
580 do
(when (< maximum
(@ i count
))
581 (setf maximum
(@ i count
))
582 (setf best-used-description k
)))
585 for i across
(@ response attributes
)
587 do
(when (< maximum
(@ i count
))
588 (setf maximum
(@ i count
))
589 (setf best-used-attribute k
))))
591 "point-attribute" attributes best-used-attribute
)
593 "point-description" descriptions best-used-description
)))
595 (defun request-user-point-choice (&optional selectp
)
596 "Stuff user point attribute comboboxes with sensible values.
597 If selectp it t, select the most frequently used one."
598 (setf (@ *streetmap
* user-point-choice-response
)
599 ((@ *open-layers
*Request
*POST
*)
600 (create :url
"/phoros/lib/user-point-attributes.json"
602 :headers
(create "Content-type" "text/plain")
604 (stuff-user-point-comboboxes selectp
))))))
606 (defun request-photos-after-click (event)
607 "Handle the response to a click into *streetmap*; fetch photo
608 data. Set or update streetmap cursor."
609 (request-photos (chain *streetmap
*
610 (get-lon-lat-from-pixel (@ event xy
)))))
612 (defun request-photos (lonlat)
613 "Fetch photo data for a point near lonlat. Set or update
615 (setf (@ *streetmap
* clicked-lonlat
) lonlat
)
616 (if (checkbox-status-with-id "walk-p")
617 (request-aux-data-linestring-for-point
618 (@ *streetmap
* clicked-lonlat
))
619 (request-photos-for-point (@ *streetmap
* clicked-lonlat
))))
621 (defun request-aux-data-linestring-for-point (lonlat-spherical-mercator)
622 "Fetch a linestring along auxiyliary points near
623 lonlat-spherical-mercator."
624 (let ((lonlat-geographic
625 (chain lonlat-spherical-mercator
627 (transform +spherical-mercator
+ +geographic
+))))
628 (request-aux-data-linestring (@ lonlat-geographic lon
)
629 (@ lonlat-geographic lat
)
630 (* *linestring-step-ratio
*
632 (step-size-degrees))))
634 (defun request-photos-for-point (lonlat-spherical-mercator)
635 "Fetch photo data near lonlat-spherical-mercator; set or
636 update streetmap cursor."
637 (disable-element-with-id "finish-point-button")
638 (disable-element-with-id "remove-work-layers-button")
639 (remove-any-layers "Estimated Position")
640 (disable-streetmap-nearest-aux-points-layer)
642 (let* ((lonlat-geographic
643 (chain lonlat-spherical-mercator
645 (transform +spherical-mercator
+ +geographic
+)))
649 (create :longitude
(@ lonlat-geographic lon
)
650 :latitude
(@ lonlat-geographic lat
)
651 :zoom
((@ *streetmap
* get-zoom
))
652 :count
(lisp *number-of-images
*))))))
655 (remove-all-features))
659 (new (chain *open-layers
665 (*point
(@ lonlat-spherical-mercator
667 (@ lonlat-spherical-mercator
670 overview-cursor-layer
671 (remove-all-features))
673 overview-cursor-layer
675 (new (chain *open-layers
681 (*point
(@ lonlat-spherical-mercator
683 (@ lonlat-spherical-mercator
685 (setf (@ *streetmap
* photo-request-response
)
686 ((@ *open-layers
*Request
*POST
*)
687 (create :url
"/phoros/lib/local-data"
689 :headers
(create "Content-type" "text/plain"
690 "Content-length" (@ content length
))
691 :success present-photos
)))))
693 (defun draw-epipolar-line ()
694 "Draw an epipolar line from response triggered by clicking
695 into a (first) photo."
696 (enable-element-with-id "remove-work-layers-button")
697 (let* ((epipolar-line
700 (@ this epipolar-request-response response-text
))))
704 (new (chain *open-layers
707 (@ x
:m
) (@ x
:n
))))))))
709 (new (chain *open-layers
715 (*line-string points
))))))))
716 (setf (@ feature render-intent
) "temporary")
717 (chain this epipolar-layer
718 (add-features feature
))))
719 ;; either *line-string or *multi-point are usable
721 (defun request-nearest-aux-points (global-position count
)
722 "Draw into streetmap the count nearest points of auxiliary
724 (let ((global-position-etc global-position
)
726 (setf (@ global-position-etc count
) count
)
727 (setf content
(chain *json-parser
*
728 (write global-position-etc
)))
729 (setf (@ *streetmap
* aux-local-data-request-response
)
730 ((@ *open-layers
*Request
*POST
*)
731 (create :url
"/phoros/lib/aux-local-data"
733 :headers
(create "Content-type" "text/plain"
736 :success draw-nearest-aux-points
)))))
738 (defun request-aux-data-linestring (longitude latitude radius step-size
)
739 "Draw into streetmap a piece of linestring threaded along the
740 nearest points of auxiliary data inside radius."
741 (let* ((payload (create longitude longitude
745 azimuth
(@ *streetmap
*
746 linestring-central-azimuth
)))
747 (content (chain *json-parser
* (write payload
))))
748 (setf (@ *streetmap
* aux-data-linestring-request-response
)
749 ((@ *open-layers
*Request
*POST
*)
750 (create :url
"/phoros/lib/aux-local-linestring.json"
752 :headers
(create "Content-type" "text/plain"
755 :success draw-aux-data-linestring
)))))
757 (defun draw-estimated-positions ()
758 "Draw into streetmap and into all images points at Estimated
759 Position. Estimated Position is the point returned so far from
760 photogrammetric calculations that are triggered by clicking into
761 another photo. Also draw into streetmap the nearest auxiliary points
762 to Estimated Position."
763 (when (write-permission-p)
764 (setf (chain document
765 (get-element-by-id "finish-point-button")
768 (enable-element-with-id "finish-point-button"))
769 (let* ((estimated-positions-request-response
773 'estimated-positions-request-response
776 (aref estimated-positions-request-response
1))
777 (estimated-position-style
778 (create stroke-color
(chain *open-layers
781 style
"temporary" stroke-color
)
784 (setf *global-position
*
785 (aref estimated-positions-request-response
0))
787 (new ((@ *open-layers
*feature
*vector
)
788 ((@ (new ((@ *open-layers
*geometry
*point
)
789 (getprop *global-position
* 'longitude
)
790 (getprop *global-position
* 'latitude
)))
791 transform
) +geographic
+ +spherical-mercator
+)))))
792 (setf (@ feature render-intent
) "temporary")
793 (setf (@ *streetmap
* estimated-position-layer
)
794 (new (chain *open-layers
798 (create display-in-layer-switcher nil
)))))
799 (setf (@ *streetmap
* estimated-position-layer style
)
800 estimated-position-style
)
801 (chain *streetmap
* estimated-position-layer
(add-features feature
))
803 (add-layer (@ *streetmap
* estimated-position-layer
))))
804 (request-nearest-aux-points *global-position
* 7)
807 for p in estimated-positions
809 (when p
;otherwise a photogrammetry error has occured
810 (setf (@ i estimated-position-layer
)
816 (create display-in-layer-switcher nil
)))))
817 (setf (@ i estimated-position-lonlat
)
818 (new (chain *open-layers
(*lon-lat
821 (setf (@ i estimated-position-layer style
)
822 estimated-position-style
)
825 (chain *open-layers
*geometry
(*point
830 (chain *open-layers
*feature
(*vector point
)))))
832 (add-layer (@ i estimated-position-layer
)))
833 (chain i estimated-position-layer
834 (add-features feature
))))))
835 (zoom-anything-to-point)
837 (get-element-by-id "finish-point-button")
840 (defun draw-nearest-aux-points ()
841 "Draw a few auxiliary points into streetmap."
842 (reveal-element-with-id "include-aux-data")
843 (reveal-element-with-id "aux-point-distance")
848 'aux-local-data-request-response
851 (disable-streetmap-nearest-aux-points-layer)
852 (chain *streetmap
* user-points-select-control
(deactivate))
853 (chain *streetmap
* nearest-aux-points-select-control
(activate))
854 (chain *streetmap
* nearest-aux-points-hover-control
(activate))
855 (setf (@ *aux-point-distance-select
* options length
)
865 (*point
(@ i geometry coordinates
0)
866 (@ i geometry coordinates
1))))
867 (transform +geographic
+ +spherical-mercator
+)))
870 (chain *open-layers
*feature
(*vector point
)))))
871 (setf (@ feature attributes
)
873 (setf (@ feature fid
) ;this is supposed to correspond to
874 n
) ; option of *aux-point-distance-select*
876 nearest-aux-points-layer
877 (add-features feature
))
878 (setf aux-point-distance-item
879 (chain document
(create-element "option")))
880 (setf (@ aux-point-distance-item text
)
883 n
;let's hope add-features alway stores features in order of arrival
887 (format (@ i properties distance
) 3 ""))))
888 (chain *aux-point-distance-select
*
889 (add aux-point-distance-item null
))))
891 nearest-aux-points-select-control
894 (elt (@ *streetmap
* nearest-aux-points-layer features
)
896 (enable-element-with-id "aux-point-distance")))
898 (defun draw-aux-data-linestring ()
899 "Draw a piece of linestring along a few auxiliary points into
900 streetmap. Pan streetmap accordingly."
903 aux-data-linestring-request-response
906 (chain *json-parser
* (read data
) linestring
))
908 (chain *json-parser
* (read data
) current-point
))
910 (chain *json-parser
* (read data
) previous-point
))
912 (chain *json-parser
* (read data
) next-point
))
914 (chain *json-parser
* (read data
) azimuth
))
916 (chain *wkt-parser
* (read linestring-wkt
)))
918 (chain *wkt-parser
* (read current-point-wkt
)))
920 (chain *wkt-parser
* (read previous-point-wkt
)))
922 (chain *wkt-parser
* (read next-point-wkt
)))
923 (current-point-lonlat
924 (new (chain *open-layers
925 (*lon-lat
(@ current-point geometry x
)
926 (@ current-point geometry y
))))))
927 (chain *streetmap
* (pan-to current-point-lonlat
))
928 (setf (@ *streetmap
* linestring-central-azimuth
) azimuth
)
929 (request-photos-for-point current-point-lonlat
)
930 (setf (@ *streetmap
* step-back-point
) previous-point
)
931 (setf (@ *streetmap
* step-forward-point
) next-point
)
932 (chain *streetmap
* aux-data-linestring-layer
(remove-all-features))
934 aux-data-linestring-layer
935 (add-features linestring
))))
937 (defun step (&optional back-p
)
938 "Enable walk-mode if necessary, and do a step along
939 aux-data-linestring."
940 (if (checkbox-status-with-id "walk-p")
941 (let ((next-point-geometry
944 (if (< (- (@ *streetmap
* linestring-central-azimuth
) pi
) 0)
945 (setf (@ *streetmap
* linestring-central-azimuth
)
946 (+ (@ *streetmap
* linestring-central-azimuth
) pi
))
947 (setf (@ *streetmap
* linestring-central-azimuth
)
948 (- (@ *streetmap
* linestring-central-azimuth
) pi
)))
953 (transform +spherical-mercator
+ +geographic
+)))
958 (transform +spherical-mercator
+ +geographic
+)))))
959 (request-aux-data-linestring (@ next-point-geometry x
)
960 (@ next-point-geometry y
)
961 (* *linestring-step-ratio
*
963 (step-size-degrees)))
965 (setf (checkbox-status-with-id "walk-p") t
) ;doesn't seem to trigger event
966 (flip-walk-mode)))) ; so we have to do it explicitly
968 (defun step-size-degrees ()
969 "Return inner-html of element step-size (metres)
970 converted into map units (degrees). You should be close to the
972 (/ (inner-html-with-id "step-size") 1855.325 60))
974 (defun decrease-step-size ()
975 (when (> (inner-html-with-id "step-size") 0.5)
976 (setf (inner-html-with-id "step-size")
977 (/ (inner-html-with-id "step-size") 2))))
979 (defun increase-step-size ()
980 (when (< (inner-html-with-id "step-size") 100)
981 (setf (inner-html-with-id "step-size")
982 (* (inner-html-with-id "step-size") 2))))
984 (defun user-point-style-map (label-property)
985 "Create a style map where styles dispatch on feature property
986 \"attribute\" and features are labelled after feature
987 property label-property."
988 (let* ((symbolizer-property "attribute")
990 (new (chain *open-layers
992 (*comparison
(create type
(chain *open-layers
996 property symbolizer-property
997 value
"solitary")))))
999 (new (chain *open-layers
1001 (*comparison
(create type
(chain *open-layers
1005 property symbolizer-property
1006 value
"polyline")))))
1008 (new (chain *open-layers
1010 (*comparison
(create type
(chain *open-layers
1014 property symbolizer-property
1015 value
"polygon")))))
1017 (new (chain *open-layers
1019 filter solitary-filter
1021 graphic-name
"triangle"))))))
1023 (new (chain *open-layers
1025 filter polyline-filter
1027 graphic-name
"square"
1028 point-radius
4))))))
1030 (new (chain *open-layers
1032 filter polygon-filter
1034 graphic-name
"star"))))))
1036 (new (chain *open-layers
1040 graphic-name
"x"))))))
1041 (user-point-default-style
1044 (*style
(create stroke-color
"OrangeRed"
1045 fill-color
"OrangeRed"
1048 font-color
"OrangeRed"
1049 font-family
"'andale mono', 'lucida console', monospace"
1054 (create rules
(array solitary-rule
1058 (user-point-select-style
1061 (*style
(create stroke-opacity
1
1062 label label-property
)
1063 (create rules
(array solitary-rule
1067 (user-point-temporary-style
1070 (*style
(create fill-opacity
.5)
1071 (create rules
(array solitary-rule
1075 (new (chain *open-layers
1077 (create "default" user-point-default-style
1078 "temporary" user-point-temporary-style
1079 "select" user-point-select-style
))))))
1081 (defun draw-user-points ()
1082 "Draw currently selected user points into all images."
1083 (let* ((user-point-positions-response
1084 (chain *json-parser
*
1086 (getprop *user-point-in-images-response
*
1088 (user-point-collections
1089 (chain user-point-positions-response image-points
))
1091 (chain user-point-positions-response user-point-count
))
1093 (when (> user-point-count
1) "${numericDescription}")))
1096 for user-point-collection in user-point-collections
1098 (when i
;otherwise a photogrammetry error has occured
1102 (@ user-point-collection features
)
1105 (@ raw-feature geometry coordinates
0))
1107 (@ raw-feature geometry coordinates
1))
1109 (new (chain *open-layers
1115 (@ raw-feature properties
))
1117 (new (chain *open-layers
1119 (*vector point attributes
)))))
1120 (setf (@ feature fid
) fid
)
1121 (setf (@ feature render-intent
) "select")
1124 (@ i user-point-layer
)
1125 (new (chain *open-layers
1129 (create display-in-layer-switcher nil
1130 style-map
(user-point-style-map
1132 (chain i map
(add-layer (@ i user-point-layer
)))
1133 (chain i user-point-layer
(add-features features
)))))))
1135 (defun finish-point ()
1136 "Send current *global-position* as a user point to the database."
1137 (let ((global-position-etc *global-position
*))
1138 (setf (@ global-position-etc attribute
)
1139 (value-with-id "point-attribute-input"))
1140 (setf (@ global-position-etc description
)
1141 (value-with-id "point-description-input"))
1142 (setf (@ global-position-etc numeric-description
)
1143 (value-with-id "point-numeric-description"))
1144 (when (checkbox-status-with-id "include-aux-data-p")
1145 (setf (@ global-position-etc aux-numeric
)
1146 (@ *current-nearest-aux-point
*
1149 (setf (@ global-position-etc aux-text
)
1150 (@ *current-nearest-aux-point
*
1154 (chain *json-parser
*
1155 (write global-position-etc
))))
1156 ((@ *open-layers
*Request
*POST
*)
1157 (create :url
"/phoros/lib/store-point"
1159 :headers
(create "Content-type" "text/plain"
1160 "Content-length" (@ content length
))
1163 (@ *streetmap
* user-point-layer
))
1164 (reset-layers-and-controls)
1165 (request-user-point-choice)))))))
1167 (defun increment-numeric-text (text)
1168 "Increment text if it looks like a number, and return it."
1169 (let* ((parts (chain (regex "(\\D*)(\\d*)(.*)") (exec text
)))
1170 (old-number (elt parts
2))
1171 (new-number (1+ (parse-int old-number
10)))))
1172 (if (is-finite new-number
)
1173 (+ (elt parts
1) new-number
(elt parts
3))
1176 (defun update-point ()
1177 "Send changes to currently selected user point to database."
1179 (create user-point-id
(@ *current-user-point
* fid
)
1181 (value-with-id "point-attribute-input")
1183 (value-with-id "point-description-input")
1185 (value-with-id "point-numeric-description")))
1187 (chain *json-parser
*
1188 (write point-data
))))
1189 ((@ *open-layers
*Request
*POST
*)
1190 (create :url
"/phoros/lib/update-point"
1192 :headers
(create "Content-type" "text/plain"
1193 "Content-length" (@ content length
))
1196 (@ *streetmap
* user-point-layer
))
1197 (reset-layers-and-controls)
1198 (request-user-point-choice))))))
1200 (defun delete-point ()
1201 "Purge currently selected user point from database."
1202 (let ((user-point-id (@ *current-user-point
* fid
)))
1204 (chain *json-parser
*
1205 (write user-point-id
)))
1206 ((@ *open-layers
*Request
*POST
*)
1207 (create :url
"/phoros/lib/delete-point"
1209 :headers
(create "Content-type" "text/plain"
1210 "Content-length" (@ content length
))
1213 (@ *streetmap
* user-point-layer
))
1214 (reset-layers-and-controls)
1215 (request-user-point-choice true
))))))
1217 (defun draw-active-point ()
1218 "Draw an Active Point, i.e. a point used in subsequent
1219 photogrammetric calculations."
1220 (chain this active-point-layer
1222 (new ((@ *open-layers
*feature
*vector
)
1223 (new ((@ *open-layers
*geometry
*point
)
1224 (getprop this
'photo-parameters
'm
)
1225 (getprop this
'photo-parameters
'n
))))))))
1227 (defun image-click-action (clicked-image)
1229 "Do appropriate things when an image is clicked into."
1231 ((@ (@ clicked-image map
) get-lon-lat-from-view-port-px
)
1234 (getprop clicked-image
'photo-parameters
))
1235 pristine-image-p content request
)
1236 (setf (@ photo-parameters m
) (@ lonlat lon
)
1237 (@ photo-parameters n
) (@ lonlat lat
))
1238 (remove-layer (getprop clicked-image
'map
) "Active Point")
1239 (remove-any-layers "Epipolar Line")
1240 (setf *pristine-images-p
* (not (some-active-point-p)))
1241 (setf (@ clicked-image active-point-layer
)
1242 (new (chain *open-layers
1244 (*vector
"Active Point"
1245 (create display-in-layer-switcher
1247 ((@ clicked-image map add-layer
)
1248 (@ clicked-image active-point-layer
))
1249 ((getprop clicked-image
'draw-active-point
))
1253 (chain *streetmap
* user-points-select-control
(unselect-all))
1255 (setf (value-with-id "point-numeric-description")
1256 (increment-numeric-text
1257 (value-with-id "point-numeric-description")))
1258 (remove-any-layers "User Point") ;from images
1260 for i across
*images
* do
1261 (unless (equal i clicked-image
)
1263 (@ i epipolar-layer
)
1264 (new (chain *open-layers
1266 (*vector
"Epipolar Line"
1268 display-in-layer-switcher nil
))))
1269 content
(chain *json-parser
*
1271 (append (array photo-parameters
)
1272 (@ i photo-parameters
))))
1273 (@ i epipolar-request-response
)
1274 ((@ *open-layers
*Request
*POST
*)
1275 (create :url
"/phoros/lib/epipolar-line"
1277 :headers
(create "Content-type" "text/plain"
1280 :success
(getprop i
'draw-epipolar-line
)
1282 ((@ i map add-layer
) (@ i epipolar-layer
)))))
1284 (remove-any-layers "Epipolar Line")
1285 (remove-any-layers "Estimated Position")
1286 (let* ((active-pointed-photo-parameters
1288 for i across
*images
*
1289 when
(has-layer-p (getprop i
'map
) "Active Point")
1290 collect
(getprop i
'photo-parameters
)))
1292 (chain *json-parser
*
1294 (list active-pointed-photo-parameters
1298 x
'photo-parameters
)))))))))
1299 (setf (@ clicked-image estimated-positions-request-response
)
1300 ((@ *open-layers
*Request
*POST
*)
1301 (create :url
"/phoros/lib/estimated-positions"
1303 :headers
(create "Content-type" "text/plain"
1306 :success
(getprop clicked-image
1307 'draw-estimated-positions
)
1308 :scope clicked-image
)))))))))
1310 (defun iso-time-string (lisp-time)
1311 "Return Lisp universal time formatted as ISO time string"
1312 (let* ((unix-time (- lisp-time
+unix-epoch
+))
1313 (js-date (new (*date
(* 1000 unix-time
)))))
1314 (chain *open-layers
*date
(to-i-s-o-string js-date
))))
1316 (defun show-photo ()
1317 "Show the photo described in this object's photo-parameters."
1319 repeat
((getprop this
'map
'get-num-layers
))
1320 do
((getprop this
'map
'layers
0 'destroy
)))
1321 (let ((image-div-width
1322 (parse-int (chain (get-computed-style (@ this map div
) nil
)
1325 (parse-int (chain (get-computed-style (@ this map div
) nil
)
1328 (getprop this
'photo-parameters
'sensor-width-pix
))
1330 (getprop this
'photo-parameters
'sensor-height-pix
)))
1331 ((getprop this
'map
'add-layer
)
1337 (photo-path (getprop this
'photo-parameters
))
1338 (new (chain *open-layers
1341 (+ image-width
.5) (+ image-height
.5))))
1342 (new (chain *open-layers
1343 (*size image-div-width
1346 max-resolution
(chain
1348 (max (/ image-width image-div-width
)
1349 (/ image-height image-div-height
))))))))
1350 (chain this map
(zoom-to-max-extent))
1351 (setf (@ this trigger-time-div inner-h-t-m-l
)
1352 (iso-time-string (getprop this
'photo-parameters
'trigger-time
)))))
1354 (defun zoom-images-to-max-extent ()
1355 "Zoom out all images."
1356 (loop for i across
*images
* do
(chain i map
(zoom-to-max-extent))))
1358 (defun zoom-anything-to-point ()
1359 "For streetmap and for images that have an Active Point or an
1360 Estimated Position, zoom in and recenter."
1361 (when (checkbox-status-with-id "zoom-to-point-p")
1363 (new (chain *open-layers
1364 (*lon-lat
(@ *global-position
* longitude
)
1365 (@ *global-position
* latitude
))
1366 (transform +geographic
+ +spherical-mercator
+)))))
1369 (set-center point-lonlat
18 nil t
))))
1370 (loop for i across
*images
* do
1373 ((has-layer-p (@ i map
) "Active Point")
1374 (new (chain *open-layers
(*lon-lat
1375 (@ i photo-parameters m
)
1376 (@ i photo-parameters n
)))))
1377 ((has-layer-p (@ i map
) "Estimated Position")
1378 (@ i estimated-position-lonlat
))
1381 (chain i map
(set-center point-lonlat
4 nil t
)))))))
1383 (defun initialize-image (image-index)
1384 "Create an image usable for displaying photos at position
1385 image-index in array *images*."
1386 (setf (aref *images
* image-index
) (new *image
))
1387 (setf (@ (aref *images
* image-index
) trigger-time-div
)
1390 (get-element-by-id (+ "image-" image-index
"-trigger-time"))))
1391 (setf (@ (aref *images
* image-index
) image-click-action
)
1392 (image-click-action (aref *images
* image-index
)))
1393 (setf (@ (aref *images
* image-index
) click
)
1394 (new (*click-control
*
1395 (create :trigger
(@ (aref *images
* image-index
)
1396 image-click-action
)))))
1397 (chain (aref *images
* image-index
)
1400 (@ (aref *images
* image-index
) click
)))
1401 (chain (aref *images
* image-index
) click
(activate))
1402 ;;(chain (aref *images* image-index)
1405 ;; (new (chain *open-layers
1411 ;; (get-element-by-id
1412 ;; (+ "image-" image-index "-zoom")))))))))
1413 (chain (aref *images
* image-index
)
1416 (new (chain *open-layers
1423 (+ "image-" image-index
"-layer-switcher")))
1424 rounded-corner nil
))))))
1425 (let ((pan-west-control
1426 (new (chain *open-layers
*control
(*pan
"West"))))
1428 (new (chain *open-layers
*control
(*pan
"North"))))
1430 (new (chain *open-layers
*control
(*pan
"South"))))
1432 (new (chain *open-layers
*control
(*pan
"East"))))
1434 (new (chain *open-layers
*control
(*zoom-in
))))
1436 (new (chain *open-layers
*control
(*zoom-out
))))
1437 (zoom-to-max-extent-control
1438 (new (chain *open-layers
*control
(*zoom-to-max-extent
))))
1440 (new (chain *open-layers
1447 (+ "image-" image-index
"-zoom")))))))))
1448 (chain (aref *images
* image-index
)
1450 (add-control pan-zoom-panel
))
1451 (chain pan-zoom-panel
1452 (add-controls (array pan-west-control
1458 zoom-to-max-extent-control
))))
1459 (chain (aref *images
* image-index
)
1461 (render (chain document
1463 (+ "image-" image-index
))))))
1465 (defun user-point-selected (event)
1466 "Things to do once a user point is selected."
1467 (remove-any-layers "Active Point")
1468 (remove-any-layers "Epipolar Line")
1469 (remove-any-layers "Estimated Position")
1470 (user-point-selection-changed))
1472 (defun user-point-unselected (event)
1473 "Things to do once a user point is unselected."
1475 (user-point-selection-changed))
1477 (defun user-point-selection-changed ()
1478 "Things to do once a user point is selected or unselected."
1479 (hide-aux-data-choice)
1480 (setf *current-user-point
*
1481 (@ *streetmap
* user-point-layer selected-features
0))
1482 (let ((selected-features-count
1483 (@ *streetmap
* user-point-layer selected-features length
)))
1484 (setf (@ *streetmap
* user-point-layer style-map
)
1485 (user-point-style-map
1486 (when (> selected-features-count
1)
1487 "${numericDescription}")))
1489 ((> selected-features-count
1)
1490 (hide-element-with-id "real-phoros-controls")
1491 (reveal-element-with-id "multiple-points-phoros-controls"))
1492 ((= selected-features-count
1)
1493 (setf (value-with-id "point-attribute-input")
1494 (@ *current-user-point
* attributes attribute
))
1495 (setf (value-with-id "point-description-input")
1496 (@ *current-user-point
* attributes description
))
1497 (setf (value-with-id "point-numeric-description")
1498 (@ *current-user-point
* attributes numeric-description
))
1499 (setf (inner-html-with-id "point-creation-date")
1500 (@ *current-user-point
* attributes creation-date
))
1501 (setf (inner-html-with-id "aux-numeric-list")
1503 (@ *current-user-point
* attributes aux-numeric
)))
1504 (setf (inner-html-with-id "aux-text-list")
1506 (@ *current-user-point
* attributes aux-text
)))
1507 (if (write-permission-p
1508 (@ *current-user-point
* attributes user-name
))
1510 (setf (chain document
1511 (get-element-by-id "finish-point-button")
1514 (enable-element-with-id "finish-point-button")
1515 (enable-element-with-id "delete-point-button")
1516 (setf (inner-html-with-id "h2-controls") "Edit Point"))
1518 (disable-element-with-id "finish-point-button")
1519 (disable-element-with-id "delete-point-button")
1520 (setf (inner-html-with-id "h2-controls") "View Point")))
1521 (setf (inner-html-with-id "creator")
1523 (@ *current-user-point
* attributes user-name
)
1526 (hide-element-with-id "multiple-points-phoros-controls")
1527 (reveal-element-with-id "real-phoros-controls"))))
1528 (chain *streetmap
* user-point-layer
(redraw))
1529 (remove-any-layers "User Point") ;from images
1531 (chain *json-parser
*
1533 (array (chain *streetmap
*
1536 (map (lambda (x) (@ x fid
))))
1538 for i across
*images
*
1539 collect
(@ i photo-parameters
))))))
1540 (setf *user-point-in-images-response
*
1541 ((@ *open-layers
*Request
*POST
*)
1542 (create :url
"/phoros/lib/user-point-positions"
1544 :headers
(create "Content-type" "text/plain"
1545 "Content-length" (@ content length
))
1546 :success draw-user-points
))))
1548 (defun aux-point-distance-selected ()
1549 "Things to do on change of aux-point-distance select element."
1551 nearest-aux-points-select-control
1554 nearest-aux-points-select-control
1557 (elt (@ *streetmap
* nearest-aux-points-layer features
)
1558 (@ *aux-point-distance-select
*
1560 selected-index
))))))
1562 (defun enable-aux-point-selection ()
1563 "Check checkbox include-aux-data-p and act accordingly."
1564 (setf (checkbox-status-with-id "include-aux-data-p") t
)
1565 (flip-aux-data-inclusion))
1567 (defun flip-walk-mode ()
1568 "Query status of checkbox walk-p and induce first walking
1569 step if it's just been turned on. Otherwise delete our
1571 (if (checkbox-status-with-id "walk-p")
1572 (request-aux-data-linestring-for-point (@ *streetmap
*
1575 aux-data-linestring-layer
1576 (remove-all-features))))
1578 (defun flip-aux-data-inclusion ()
1579 "Query status of checkbox include-aux-data-p and act
1581 (if (checkbox-status-with-id "include-aux-data-p")
1583 nearest-aux-points-layer
1586 nearest-aux-points-layer
1587 (set-visibility nil
))))
1589 (defun html-ordered-list (aux-data)
1590 "Return a html-formatted list from aux-data."
1593 (:ol
:class
"aux-data-list"
1595 (reduce (lambda (x y
)
1596 (+ x
(who-ps-html (:li y
))))
1600 (defun nearest-aux-point-selected (event)
1601 "Things to do once a nearest auxiliary point is selected in streetmap."
1602 (setf *current-nearest-aux-point
* (@ event feature
))
1604 (@ event feature attributes aux-numeric
))
1606 (@ event feature attributes aux-text
))
1608 (@ event feature attributes distance
)))
1609 (setf (@ *aux-point-distance-select
* options selected-index
)
1610 (@ event feature fid
))
1611 (setf (inner-html-with-id "aux-numeric-list")
1612 (html-ordered-list aux-numeric
))
1613 (setf (inner-html-with-id "aux-text-list")
1614 (html-ordered-list aux-text
))))
1617 "Store user's current map extent and log out."
1618 (let* ((bbox (chain *streetmap
*
1620 (transform +spherical-mercator
+ +geographic
+)
1622 (href (+ "/phoros/lib/logout?bbox=" bbox
)))
1623 (when (@ *streetmap
* cursor-layer features length
)
1624 (let* ((lonlat-geographic (chain *streetmap
*
1630 (transform +spherical-mercator
+
1633 "&longitude=" (@ lonlat-geographic x
)
1634 "&latitude=" (@ lonlat-geographic y
)))))
1635 (setf (@ location href
) href
)))
1638 "Prepare user's playground."
1639 (unless +presentation-project-bbox-text
+
1640 (setf (inner-html-with-id "presentation-project-emptiness")
1646 (create projection
+geographic
+
1647 display-projection
+geographic
+
1648 controls
(array (new (chain *open-layers
1651 (new (chain *open-layers
1653 (*attribution
)))))))))
1654 (unless +aux-data-p
+
1655 (disable-element-with-id "walk-p")
1656 (hide-element-with-id "decrease-step-size")
1657 (hide-element-with-id "step-size")
1658 (hide-element-with-id "increase-step-size")
1659 (hide-element-with-id "step-button"))
1660 (when (write-permission-p)
1661 (enable-element-with-id "point-attribute-input")
1662 (enable-element-with-id "point-attribute-select")
1663 (enable-element-with-id "point-description-input")
1664 (enable-element-with-id "point-description-select")
1665 (enable-element-with-id "point-numeric-description")
1666 (request-user-point-choice true
))
1667 (setf (inner-html-with-id "h2-controls") "Create Point")
1668 (hide-element-with-id "multiple-points-phoros-controls")
1669 (setf *point-attributes-select
*
1670 (chain document
(get-element-by-id "point-attribute-select")))
1671 (setf *aux-point-distance-select
*
1672 (chain document
(get-element-by-id "aux-point-distance")))
1673 (hide-aux-data-choice)
1674 (let ((cursor-layer-style
1677 external-graphic
"/phoros/lib/public_html/phoros-cursor.png")))
1678 (setf (@ *streetmap
* cursor-layer
)
1684 style cursor-layer-style
)))))
1685 (setf (@ *streetmap
* overview-cursor-layer
)
1691 style cursor-layer-style
))))))
1692 (let ((survey-layer-style
1693 (create stroke-color
(chain *open-layers
*feature
*vector
1694 style
"default" stroke-color
)
1698 graphic-name
"circle")))
1699 (setf (@ *streetmap
* survey-layer
)
1705 strategies
(array (new (*bbox-strategy
*)))
1707 (new (*http-protocol
*
1708 (create :url
"/phoros/lib/points.json")))
1709 style survey-layer-style
))))))
1710 (setf (@ *streetmap
* user-point-layer
)
1716 strategies
(array (new *bbox-strategy
*))
1718 (new (*http-protocol
*
1719 (create :url
"/phoros/lib/user-points.json")))
1720 style-map
(user-point-style-map nil
))))))
1721 (setf (@ *streetmap
* user-points-hover-control
)
1722 (new (chain *open-layers
1724 (*select-feature
(@ *streetmap
* user-point-layer
)
1725 (create render-intent
"temporary"
1727 highlight-only t
)))))
1728 (setf (@ *streetmap
* user-points-select-control
)
1729 (new (chain *open-layers
1731 (*select-feature
(@ *streetmap
* user-point-layer
)
1734 (let ((aux-layer-style
1735 (create stroke-color
"grey"
1739 graphic-name
"circle")))
1740 (setf (@ *streetmap
* aux-point-layer
)
1746 strategies
(array (new (*bbox-strategy
*)))
1748 (new (*http-protocol
*
1749 (create :url
"/phoros/lib/aux-points.json")))
1750 style aux-layer-style
1751 visibility nil
))))))
1752 (let ((nearest-aux-point-layer-style-map
1753 (new (chain *open-layers
1756 (create stroke-color
"grey"
1760 graphic-name
"circle")
1762 (create stroke-color
"black"
1766 graphic-name
"circle")
1768 (create stroke-color
"grey"
1773 graphic-name
"circle")))))))
1774 (setf (@ *streetmap
* nearest-aux-points-layer
)
1775 (new (chain *open-layers
1778 "Nearest Aux Points"
1780 display-in-layer-switcher nil
1781 style-map nearest-aux-point-layer-style-map
1783 (setf (@ *streetmap
* nearest-aux-points-hover-control
)
1784 (new (chain *open-layers
1787 (@ *streetmap
* nearest-aux-points-layer
)
1788 (create render-intent
"temporary"
1790 highlight-only t
)))))
1791 (setf (@ *streetmap
* nearest-aux-points-select-control
)
1792 (new (chain *open-layers
1795 (@ *streetmap
* nearest-aux-points-layer
)))))
1796 (setf (@ *streetmap
* aux-data-linestring-layer
)
1797 (new (chain *open-layers
1800 "Aux Data Linestring"
1802 display-in-layer-switcher nil
1803 style-map nearest-aux-point-layer-style-map
1805 (setf (@ *streetmap
* google-streetmap-layer
)
1806 (new (chain *open-layers
1808 (*google
"Google Streets"
1809 (create num-zoom-levels
23)))))
1810 (setf (@ *streetmap
* osm-layer
)
1811 (new (chain *open-layers
1816 (create num-zoom-levels
23
1818 "Data CC-By-SA by openstreetmap.org")))))
1819 (setf (@ *streetmap
* overview-osm-layer
)
1820 (new (chain *open-layers
1822 (*osm
* "OpenStreetMap"))))
1823 (setf (@ *streetmap
* click-streetmap
)
1824 (new (*click-control
*
1825 (create :trigger request-photos-after-click
))))
1826 (setf (@ *streetmap
* nirvana-layer
)
1831 (create is-base-layer t
1832 projection
(@ *streetmap
* osm-layer projection
)
1833 max-extent
(@ *streetmap
* osm-layer max-extent
)
1834 max-resolution
(@ *streetmap
*
1837 units
(@ *streetmap
* osm-layer units
)
1838 num-zoom-levels
(@ *streetmap
*
1840 num-zoom-levels
))))))
1843 (new (chain *open-layers
1850 "streetmap-layer-switcher"))
1851 rounded-corner nil
))))))
1852 (let ((pan-west-control
1853 (new (chain *open-layers
*control
(*pan
"West"))))
1855 (new (chain *open-layers
*control
(*pan
"North"))))
1857 (new (chain *open-layers
*control
(*pan
"South"))))
1859 (new (chain *open-layers
*control
(*pan
"East"))))
1861 (new (chain *open-layers
*control
(*zoom-in
))))
1863 (new (chain *open-layers
*control
(*zoom-out
))))
1864 (zoom-to-max-extent-control
1870 display-class
"streetmapZoomToMaxExtent"
1874 +presentation-project-bounds
+ ))))))))
1876 (new (chain *open-layers
1883 "streetmap-zoom")))))))
1885 (new (chain *open-layers
1891 (@ *streetmap
* overview-osm-layer
)
1892 (@ *streetmap
* overview-cursor-layer
))
1898 "streetmap-overview")))))))
1899 (mouse-position-control
1900 (new (chain *open-layers
1903 (create div
(chain document
1905 "streetmap-mouse-position"))
1906 empty-string
"longitude, latitude")))))
1908 (new (chain *open-layers
1912 (add-control pan-zoom-panel
))
1913 (chain pan-zoom-panel
1914 (add-controls (array pan-west-control
1920 zoom-to-max-extent-control
)))
1922 (add-control (@ *streetmap
* click-streetmap
)))
1923 (chain *streetmap
* click-streetmap
(activate))
1928 (register "featureselected"
1929 (@ *streetmap
* user-point-layer
)
1930 user-point-selected
))
1934 (register "featureunselected"
1935 (@ *streetmap
* user-point-layer
)
1936 user-point-unselected
))
1938 nearest-aux-points-layer
1940 (register "featureselected"
1941 (@ *streetmap
* nearest-aux-points-layer
)
1942 nearest-aux-point-selected
))
1945 (@ *streetmap
* nearest-aux-points-hover-control
)))
1948 (@ *streetmap
* nearest-aux-points-select-control
)))
1951 (@ *streetmap
* user-points-hover-control
)))
1954 (@ *streetmap
* user-points-select-control
)))
1955 (chain *streetmap
* user-points-hover-control
(activate))
1956 (chain *streetmap
* user-points-select-control
(activate))
1957 (chain *streetmap
* nearest-aux-points-hover-control
(activate))
1958 (chain *streetmap
* nearest-aux-points-select-control
(activate))
1959 (chain *streetmap
* (add-layer (@ *streetmap
* osm-layer
)))
1960 (try (chain *streetmap
*
1961 (add-layer (@ *streetmap
* google-streetmap-layer
)))
1964 (remove-layer (@ *streetmap
*
1965 google-streetmap-layer
)))))
1966 (chain *streetmap
* (add-layer (@ *streetmap
* nirvana-layer
)))
1968 (add-layer (@ *streetmap
* nearest-aux-points-layer
)))
1969 (chain *streetmap
* (add-layer (@ *streetmap
* survey-layer
)))
1971 (add-layer (@ *streetmap
* cursor-layer
)))
1973 (add-layer (@ *streetmap
* aux-point-layer
)))
1975 (add-layer (@ *streetmap
* aux-data-linestring-layer
)))
1977 (add-layer (@ *streetmap
* user-point-layer
)))
1978 (setf (@ overview-map element
)
1979 (chain document
(get-element-by-id
1980 "streetmap-overview-element")))
1981 (chain *streetmap
* (add-control overview-map
))
1982 (chain *streetmap
* (add-control mouse-position-control
))
1983 (chain *streetmap
* (add-control scale-line-control
)))
1985 for i from
0 to
(lisp (1- *number-of-images
*))
1986 do
(initialize-image i
))
1990 (if (lisp (stored-bbox))
1991 (new (chain *open-layers
1993 (from-string (lisp (stored-bbox)))
1994 (transform +geographic
+ +spherical-mercator
+)))
1995 +presentation-project-bounds
+)))
1996 (let ((stored-cursor (lisp (stored-cursor))))
1999 (new (chain *open-layers
2001 (from-string stored-cursor
)
2002 (transform +geographic
+
2003 +spherical-mercator
+)))))))))))
2005 (pushnew (hunchentoot:create-regex-dispatcher
2006 (format nil
"/phoros/lib/phoros-~A-\\S*-\\S*\.js"
2009 hunchentoot
:*dispatch-table
*)