IMHOTEP Framework
 All Classes Namespaces Functions Variables Enumerations Enumerator Properties Pages
AnnotationControl.cs
1 using UnityEngine;
2 using System.Collections;
3 using UnityEngine.UI;
4 using UnityEngine.EventSystems;
5 using System.Collections.Generic;
6 using LitJson;
7 using System;
8 using System.IO;
9 
10 // TODO: Move saving and loading to Patient? I think the Patient class should have all info...
11 // That way any other widget/tool can access the annotations as well, if needed in the future.
12 
13 //This class represents the annotiation points in a JSON file. It can be stored and loaded with the JSON mapper.
14 using System.Linq;
15 
16 
17 public class AnnotationJson
18 {
19  public string Text;
20  public AnnotationControl.AnnotationType type;
21 
22  public float ColorR;
23  public float ColorG;
24  public float ColorB;
25 
26  public float ScaleX;
27  public float ScaleY;
28  public float ScaleZ;
29 
30  public double PositionX;
31  public double PositionY;
32  public double PositionZ;
33 
34  public double RotationW;
35  public double RotationX;
36  public double RotationY;
37  public double RotationZ;
38 
39  public double MeshRotationW;
40  public double MeshRotationX;
41  public double MeshRotationY;
42  public double MeshRotationZ;
43 
44 
45  public string Creator;
46  public DateTime CreationDate;
47 
48 }
49 
50 public class AnnotationControl : MonoBehaviour
51 {
52  //Prefabs
53  public GameObject annotationPinGroupObj;
54  public GameObject annotationPlaneGroupObj;
55  public GameObject annotationSphereGroupObj;
56 
57  public GameObject annotationLabel;
58  public GameObject annotationListEntry;
59  public GameObject annotationToolBar;
60 
61  //instance
62  public static AnnotationControl instance;
63 
64 
65  //Screens
66  public GameObject ListScreen;
67  public GameObject AddEditScreen;
68 
69  //Add Annotation Screen Things
70  public GameObject instructionText;
71  public GameObject annotationSettings;
72 
73  public GameObject meshNode;
74  public GameObject meshPositionNode;
75 
76  //States
77  private ActiveScreen currentActiveScreen = ActiveScreen.none;
78 
79  //current is the edited of actual Object to reset when abort is pressed
80  private AnnotationType currentAnnotationType;
81  private GameObject currentAnnotationListEntry = null;
82 
83  private List<GameObject> annotationListEntryList = new List<GameObject> ();
84  private GameObject previewAnnotation;
85 
86  private ClickNotifier clickNotifier;
87 
88  //Transparencys
89  public float previewTransparency = 0.2f;
90  public float editAnnotationTransparency = 0.2f;
91  public float defaultTransperency = 0.4f;
92  public float organTransparency = 0.4f;
93 
94 
95  //The State of Annotation Control, which scrren is active
96  // none , no screen is active
97  // add , add screen is active
98  // list, list screen is active
99  private enum ActiveScreen
100  {
101  none,
102  add,
103  list
104  }
105 
106  public enum AnnotationType {
107  pin,
108  plane,
109  sphere
110  }
111 
112  public AnnotationControl()
113  {
114  if( instance != null )
115  throw(new System.Exception ("Error: Cannot create more than one instance of ANNOTATIONCONTROL!"));
116  instance = this;
117 
118  }
119 
120  void OnEnable ()
121  {
122  // Register event callbacks:
123  AddEditScreen.SetActive (false);
124  ListScreen.SetActive (false);
125  annotationToolBar.SetActive (true);
126  currentActiveScreen = ActiveScreen.none;
127 
128  setAllAnnotationsActive (true);
129 
130  annotationLabel.SetActive (false);
131  annotationPinGroupObj.SetActive (false);
132  annotationPlaneGroupObj.SetActive (false);
133  annotationSphereGroupObj.SetActive (false);
134  annotationListEntry.gameObject.SetActive (false);
135 
136  clickNotifier = meshPositionNode.AddComponent<ClickNotifier> ();
137  clickNotifier.clickNotificationEvent = OnMeshClicked;
138  clickNotifier.hoverNotificationEvent = hoveredOverMesh;
139  clickNotifier.exitNotificationEvent = pointerExitMesh;
140  }
141 
142  void OnDisable ()
143  {
144  // Unregister myself:
145  clearAll ();
146  Destroy (clickNotifier);
147  }
148 
149 
150  // Use this for initialization
151  void Start ()
152  {
153 
154  if (annotationPinGroupObj == null) {
155  Debug.LogError ("No Annotation Pin Object is set in AnnotationControl.cs");
156  }
157  if (annotationPlaneGroupObj == null) {
158  Debug.LogError ("No Annotation Plane Object is set in AnnotationControl.cs");
159  }
160  if (annotationSphereGroupObj == null) {
161  Debug.LogError ("No Annotation Sphere Object is set in AnnotationControl.cs");
162  }
163 
164 
165  }
166 
167  //################ Called By Buttons ###############
168 
169  //Called if the user pressed 'add annoation' button
170  public void AddAnnotationPressed ()
171  {
172  if (currentActiveScreen == ActiveScreen.add) {
173  closeAnnotationScreen ();
174  } else {
175  //Open AnnotationScreen
176  if (currentAnnotationListEntry == null) {
177  instructionText.SetActive (true);
178  enableOrgans ();
179  currentAnnotationType = AnnotationType.pin;
180  createPreviewAnnotation ();
181  openAnnotationScreen ();
182  }
183 
184  }
185  }
186 
187  //Called if the user pressed 'show Annotation' button
188  public void ToggleAnnotationsList ()
189  {
190  if (currentActiveScreen == ActiveScreen.list) {
191  // Close AnnotationListScreen
192  ListScreen.SetActive (false);
193  currentActiveScreen = ActiveScreen.none;
194  } else {
195  //Open AnnotationListScreen
196  closeAnnotationScreen ();
197  ListScreen.SetActive (true);
198  currentActiveScreen = ActiveScreen.list;
199  }
200  }
201  //Called by Color Button with it self as Attribut
202  public void ChangeColorPressed (GameObject newColorButton)
203  {
204  if (currentAnnotationListEntry != null) {
205  currentAnnotationListEntry.GetComponent<AnnotationListEntry> ().changeAnnotationColor (
206  newColorButton.GetComponent<Button> ().colors.normalColor);
207  }
208  if (previewAnnotation != null) {
209  previewAnnotation.GetComponent<Annotation> ().changeColor (
210  newColorButton.GetComponent<Button> ().colors.normalColor);
211  }
212  updatePatientAnnotationList ();
213  }
214 
215  public void changeAnnoTypeToPin () {
216  changeCurrentAnnotationType(AnnotationType.pin);
217  }
218 
219  public void changeAnnoTypeToPlane () {
220  changeCurrentAnnotationType(AnnotationType.plane);
221  }
222 
223  public void changeAnnoTypeToSphere () {
224  changeCurrentAnnotationType(AnnotationType.sphere);
225  }
226 
227  //################ Called By Events ################
228 
229  // Called when user clicks on Organ
230  public void OnMeshClicked (PointerEventData eventData)
231  {
232  if (eventData.button != PointerEventData.InputButton.Left) {
233  return;
234  }
235  //Click on Organ
236  if (currentActiveScreen == ActiveScreen.add) {
237  Vector3 localpos = meshPositionNode.transform.InverseTransformPoint (eventData.pointerPressRaycast.worldPosition);
238  Vector3 localNormal = meshPositionNode.transform.InverseTransformDirection (eventData.pointerPressRaycast.worldNormal);
239  if (currentAnnotationListEntry == null) {
240  GameObject newAnnotation = createAnnotationGroup (currentAnnotationType, Quaternion.LookRotation (localNormal), localpos);
241  //add to List
242  EditAnnotation (createNewAnnotationListEntry (newAnnotation));
243  } else if (currentAnnotationType == AnnotationType.pin){
244  changeAnnotationPosition (Quaternion.LookRotation (localNormal), localpos);
245  }
246  }
247 
248 
249  }
250 
251  //Called by Hover Organ Event
252  public void hoveredOverMesh (PointerEventData eventData)
253  {
254  if (previewAnnotation != null) {
255  if(!eventData.pointerEnter.gameObject.CompareTag("AnnotationLabel") && !eventData.pointerEnter.gameObject.CompareTag("Annotation")) {
256  previewAnnotation.SetActive (true);
257  Vector3 localpos = meshPositionNode.transform.InverseTransformPoint (eventData.pointerCurrentRaycast.worldPosition);
258  Vector3 localNormal = meshPositionNode.transform.InverseTransformDirection (eventData.pointerCurrentRaycast.worldNormal);
259  previewAnnotation.GetComponent<Annotation> ().updatePosition (Quaternion.LookRotation (localNormal), localpos);
260  } else {
261  previewAnnotation.SetActive (false);
262  }
263  }
264  }
265 
266  //Called if pointer is noty anymore on Mesh
267  public void pointerExitMesh (PointerEventData eventData)
268  {
269  if (previewAnnotation != null) {
270  previewAnnotation.SetActive (false);
271  }
272  }
273 
274  //################ Private Methods #################
275 
276 
277  private void setAllAnnotationsActive(bool active) {
278  foreach(GameObject g in annotationListEntryList) {
279  if(g!= null) {
280  setAnnotationActive (g, active);
281  }
282  }
283  }
284 
285  private void enableAllAnnotationCollider(bool enable) {
286 
287  if(annotationListEntryList == null || annotationListEntryList.Count == 0) {
288  return;
289  }
290  foreach(GameObject g in annotationListEntryList) {
291  if(g!= null) {
292  g.GetComponent<AnnotationListEntry> ().enableAllCollider (enable);
293  }
294  }
295  }
296 
297 
298 
299 
300 
301 
302  private void setAnnotationActive(GameObject aListentry, bool active) {
303  aListentry.GetComponent<AnnotationListEntry> ().setMyAnnotationActive (active);
304  }
305 
306  private void setCurrentAnnotationListEntry(GameObject anno) {
307  currentAnnotationListEntry = anno;
308  GetComponent<LabelPositioner> ().forceRecalculate ();
309  currentAnnotationType = anno.GetComponent<AnnotationListEntry> ().getMyAnnotationType ();
310  }
311 
312  private void resetCurrentAnnotation() {
313  currentAnnotationListEntry = null;
314  }
315 
316 
317 
318  private void disableOrgans() {
319  GameObject.Find ("GlobalScript").GetComponent<HierarchicalInputModule> ().disableLayer ("MeshViewer");
320  meshPositionNode.GetComponent<OpacityOfAllChanger> ().changeOpacityofAll (organTransparency);
321  }
322 
323  private void enableOrgans() {
324  GameObject.Find ("GlobalScript").GetComponent<HierarchicalInputModule> ().enableLayer ("MeshViewer");
325  meshPositionNode.GetComponent<OpacityOfAllChanger> ().changeOpacityofAll (1f);
326  }
327 
328  private void makeAnnotationsTransparent() {
329  foreach(GameObject g in annotationListEntryList) {
330  if(g != currentAnnotationListEntry) {
331  g.GetComponent<AnnotationListEntry> ().makeAnnotationTransparent (editAnnotationTransparency);
332  }
333  }
334  }
335 
336  private void resetAnnotationTransparency() {
337  foreach(GameObject g in annotationListEntryList) {
338  if(g != currentAnnotationListEntry) {
339  g.GetComponent<AnnotationListEntry> ().resetAnnotationTransparency ();
340  }
341  }
342  }
343 
344  private void changeCurrentAnnotationType(AnnotationType newType) {
345  if(currentAnnotationListEntry == null) {
346  currentAnnotationType = newType;
347  createPreviewAnnotation ();
348  } else {
349  changeAnnoTypeTo (currentAnnotationListEntry, newType);
350  updateListInLabelPositioner ();
351  EditAnnotation (currentAnnotationListEntry);
352  }
353  }
354 
355  private void changeAnnoTypeTo(GameObject annotationGroup, AnnotationType newType) {
356  if(annotationGroup != null) {
357  currentAnnotationType = newType;
358  GameObject curAnnoGroup = annotationGroup.GetComponent<AnnotationListEntry> ().getAnnotation ();
359  GameObject newAnnoGroup = createAnnotationGroup (newType, curAnnoGroup.GetComponent<Transform> ().localRotation, curAnnoGroup.GetComponent<Transform> ().localPosition);
360  annotationGroup.GetComponent<AnnotationListEntry> ().replaceMyAnnotationMesh (newAnnoGroup);
361  updatePatientAnnotationList ();
362  }
363  }
364 
365 
366  private void jumpToListEntry (GameObject annotation)
367  {
368  if (currentActiveScreen == ActiveScreen.list) {
369  GameObject listEntry = annotation.GetComponent<Annotation> ().myAnnotationListEntry;
370  Vector2 pos = listEntry.gameObject.GetComponent<AnnotationListEntry> ().getListPos ();
371  listEntry.transform.parent.GetComponent<RectTransform> ().anchoredPosition =
372  new Vector2 (0.0f, (-(pos.y) - (ListScreen.GetComponent<RectTransform> ().rect.height / 3)));
373  }
374  }
375 
376  private void createPreviewAnnotation ()
377  {
378  //Clone Annotation
379  GameObject annotationType = getAnnotationTypeObject (currentAnnotationType);
380  Color c = new Color ();
381  bool newColor = false;
382 
383  if(previewAnnotation != null) {
384  c = previewAnnotation.GetComponent<Annotation> ().getColor ();
385  Destroy (previewAnnotation);
386  newColor = true;
387  }
388  previewAnnotation = (GameObject)Instantiate (annotationType);
389 
390  previewAnnotation.transform.localScale = new Vector3 (5, 5, 5);
391  previewAnnotation.transform.SetParent (meshPositionNode.transform, false);
392  //SetSettings
393  previewAnnotation.SetActive (true);
394  previewAnnotation.GetComponent<Annotation> ().makeTransperent (previewTransparency);
395  previewAnnotation.GetComponent<Annotation> ().disableMeshCollider ();
396  if(newColor) {
397  previewAnnotation.GetComponent<Annotation> ().changeColor (c);
398  } else {
399  previewAnnotation.GetComponent<Annotation> ().setDefaultColor ();
400  }
401  }
402 
403 
404  private GameObject getAnnotationTypeObject (AnnotationType type) {
405  GameObject annotationType;
406  switch(type) {
407  case AnnotationType.pin:
408  annotationType = annotationPinGroupObj;
409  break;
410  case AnnotationType.plane:
411  annotationType = annotationPlaneGroupObj;
412  break;
413  case AnnotationType.sphere:
414  annotationType = annotationSphereGroupObj;
415  break;
416  default:
417  annotationType = annotationPinGroupObj;
418  break;
419  }
420  return annotationType;
421  }
422 
423 
424  //Used to Create Annotation Mesh
425  // Local Position
426  private GameObject createAnnotationGroup (AnnotationType annoType, Quaternion rotation, Vector3 position)
427  {
428  GameObject annotationType = getAnnotationTypeObject (annoType);
429  GameObject newAnnotation = (GameObject)Instantiate (annotationType, position, rotation);
430 
431  newAnnotation.transform.localScale = new Vector3 (5, 5, 5);
432  newAnnotation.transform.SetParent (meshPositionNode.transform, false);
433 
434  newAnnotation.SetActive (true);
435 
436  //set Type
437  newAnnotation.GetComponent<Annotation>().myType = annoType;
438 
439  //Create Label for annotation
440  newAnnotation.GetComponent<Annotation> ().CreateLabel (annotationLabel);
441 
442  //set Color
443  if(previewAnnotation != null) {
444  newAnnotation.GetComponent<Annotation> ().changeColor(previewAnnotation.GetComponent<Annotation>().getColor());
445  } else {
446  newAnnotation.GetComponent<Annotation> ().setDefaultColor ();
447  }
448 
449  newAnnotation.GetComponent<Annotation> ().setDefaultTransparency ();
450 
451  return newAnnotation;
452  }
453 
454  //Swap image of Annotation button
455  public void closeAnnotationScreen ()
456  {
457  enableOrgans ();
458  // Reset Screen
459  if(currentAnnotationListEntry != null) {
460  currentAnnotationListEntry.GetComponent<AnnotationListEntry> ().setAnnotationMovementActive (false);
461  }
462  resetCurrentAnnotation ();
463  Destroy (previewAnnotation);
464  previewAnnotation = null;
465 
466  //Reset Edit Tools
467  resetAnnotationTransparency();
468  instructionText.gameObject.SetActive (true);
469  // Close Screen
470  AddEditScreen.SetActive (false);
471  currentActiveScreen = ActiveScreen.none;
472 
473  //save changes when close screen
474  updatePatientAnnotationList ();
475 
476  }
477 
478  //Opens AnnotationScreen
479  private void openAnnotationScreen ()
480  {
481  //open Screen
482  makeAnnotationsTransparent();
483  ListScreen.SetActive (false);
484  AddEditScreen.SetActive (true);
485  currentActiveScreen = ActiveScreen.add;
486  }
487 
488  //Change Annotation Position
489  private void changeAnnotationPosition (Quaternion rotation, Vector3 position)
490  {
491  currentAnnotationListEntry.GetComponent<AnnotationListEntry> ().updateAnnotationposition (rotation, position);
492  updatePatientAnnotationList ();
493  }
494 
495  //Creates a new AnnotationListEntry, gets the Annotation to this entry, does not add to list
496  private GameObject createNewAnnotationListEntry (GameObject annotation)
497  {
498  if (annotation != null) {
499 
500  // Create a new instance of the list button:
501  GameObject newEntry = Instantiate (annotationListEntry).gameObject;
502  newEntry.SetActive (true);
503 
504  // Attach the new Entry to the list:
505  newEntry.transform.SetParent (annotationListEntry.transform.parent, false);
506 
507  newEntry.GetComponent<AnnotationListEntry> ().setupListEntry (annotation);
508 
509  annotationListEntryList.Add (newEntry);
510  updateListInLabelPositioner ();
511  return newEntry;
512  } else {
513  Debug.LogAssertion ("Annotation is Null");
514  }
515  return null;
516  }
517 
518  //removes a annotation given in self from view
519  private void removeOneAnnotation (GameObject aListEntry)
520  {
521 
522  if(currentAnnotationListEntry == aListEntry)
523  {
524  resetCurrentAnnotation ();
525  }
526  //delete Annotation Mesh
527  aListEntry.GetComponent<AnnotationListEntry> ().DestroyAnnotation ();
528 
529  Destroy (aListEntry);
530  }
531 
532  //################ Other Methods ##################
533 
534 
535 
536  public bool isCurrentAnnotation(GameObject annotation) {
537  if(currentAnnotationListEntry == null) {
538  return false;
539  }
540  if(annotation == currentAnnotationListEntry.GetComponent<AnnotationListEntry>().getAnnotation()) {
541  return true;
542  }
543  return false;
544  }
545 
546  public void updateListInLabelPositioner() {
547  GetComponent<LabelPositioner> ().updateAnnotationList (getAnnotationList ());
548  }
549 
550  public List<GameObject> getAnnotationList() {
551  List<GameObject> returnList = new List<GameObject> ();
552  if(annotationListEntryList != null) {
553  foreach(GameObject g in annotationListEntryList) {
554  returnList.Add (g.GetComponent<AnnotationListEntry>().getAnnotation());
555  }
556  }
557  return returnList;
558  }
559 
560  public void resetLayers() {
561  GameObject inMod = GameObject.Find ("GlobalScript");
562  if(inMod != null) {
563  inMod.GetComponent<HierarchicalInputModule> ().resetLayerMask ();
564  }
565  }
566 
572  public bool annotationClicked(PointerEventData data) {
573  if(currentAnnotationListEntry == data.pointerEnter.GetComponentInParent<Annotation> ().myAnnotationListEntry) {
574  return true;
575  }
576  if (currentActiveScreen == ActiveScreen.list) {
577  jumpToListEntry (data.pointerEnter);
578  } else {
579  if (currentAnnotationListEntry != null || currentActiveScreen == ActiveScreen.add) {
580  closeAnnotationScreen ();
581  }
582  EditAnnotation (data.pointerEnter.GetComponentInParent<Annotation> ().myAnnotationListEntry);
583  }
584  return false;
585  }
586 
587  // deleteall Annotations
588  public void deleteAllAnnotations ()
589  {
590  foreach (GameObject g in annotationListEntryList) {
591  if (g != null) {
592  removeOneAnnotation (g);
593  }
594  }
595 
596  currentAnnotationListEntry = null;
597  //Delete hoverAnnotation
598  Destroy (previewAnnotation);
599  previewAnnotation = null;
600  annotationListEntryList = new List<GameObject> ();
601  updatePatientAnnotationList ();
602  }
603 
604 
605  // deactivates all Annotations
606  public void clearAll ()
607  {
608  setAllAnnotationsActive (false);
609  currentAnnotationListEntry = null;
610  //Delete hoverAnnotation
611  Destroy (previewAnnotation);
612  previewAnnotation = null;
613 
614  }
615 
616  //Called by load Method in Patient to Create all Annotations in File
617  public void createAnnotation(AnnotationJson annotation) {
618  Quaternion rotation = new Quaternion ((float)annotation.RotationX, (float)annotation.RotationY, (float)annotation.RotationZ, (float)annotation.RotationW);
619  Quaternion meshRotation = new Quaternion ((float)annotation.MeshRotationX, (float)annotation.MeshRotationY, (float)annotation.MeshRotationZ, (float)annotation.MeshRotationW);
620  Vector3 position = new Vector3 ((float)annotation.PositionX, (float)annotation.PositionY, (float)annotation.PositionZ);
621 
622  //setup new Annotation as maesh and in List
623  GameObject newAnnotation = createAnnotationGroup (annotation.type, rotation, position);
624  if(annotation.type == AnnotationType.plane || annotation.type == AnnotationType.sphere) {
625  newAnnotation.GetComponent<Annotation> ().myAnnotationMesh.transform.localRotation = meshRotation;
626  }
627 
628  newAnnotation.GetComponent<Annotation> ().setLabeText (annotation.Text);
629 
630  //Color not empty (Black)
631  if (annotation.ColorR != 0.0f || annotation.ColorG != 0.0f || annotation.ColorB != 0.0f) {
632  newAnnotation.GetComponent<Annotation> ().changeColor (new Color (annotation.ColorR, annotation.ColorG, annotation.ColorB));
633  }
634  if(annotation.ScaleX == 0f) {
635  newAnnotation.GetComponent<Annotation> ().rescaleMesh (new Vector3 (1f, 1f, 1f));
636  } else {
637  newAnnotation.GetComponent<Annotation> ().rescaleMesh (new Vector3(annotation.ScaleX, annotation.ScaleY, annotation.ScaleZ));
638  }
639 
640  createNewAnnotationListEntry (newAnnotation);
641  }
642 
643 
644  //updates list in Patient ... will be safed in file by Patient class
645  public void updatePatientAnnotationList()
646  {
647  Patient p = Patient.getLoadedPatient ();
648  if (p != null)
649  p.updateAnnotationList (annotationListEntryList);
650  }
651 
652  //Called to edit Annotation
653  public void EditAnnotation (GameObject aListEntry)
654  {
655  if(currentAnnotationListEntry == null) {
656  setCurrentAnnotationListEntry (aListEntry);
657  }
658  if(currentAnnotationType == AnnotationType.plane) {
659  //delete preview
660  Destroy(previewAnnotation);
661  previewAnnotation = null;
662  disableOrgans ();
663  } else if(currentAnnotationType == AnnotationType.sphere) {
664  //delete preview
665  Destroy(previewAnnotation);
666  previewAnnotation = null;
667  disableOrgans ();
668  } else {
669  createPreviewAnnotation ();
670  previewAnnotation.GetComponent<Annotation> ().changeColor (
671  currentAnnotationListEntry.GetComponent<AnnotationListEntry> ().getAnnotationColor ());
672  enableOrgans ();
673  }
674 
675  currentAnnotationListEntry.GetComponent<AnnotationListEntry> ().setAnnotationMovementActive (true);
676  instructionText.SetActive (false);
677  openAnnotationScreen ();
678  }
679 
680  //Called by AnnotationListEntryControl with the annotation to delete form view and File
681  public void DeleteAnnotation (GameObject aListEntry)
682  {
683  //delete List Entry
684  annotationListEntryList.Remove (aListEntry);
685  removeOneAnnotation (aListEntry);
686  updateListInLabelPositioner ();
687  //delete in File (save new File)
688  updatePatientAnnotationList ();
689  }
690 }
bool annotationClicked(PointerEventData data)
Called by Annotation when Clicked on Annotation