private void UpdateAnnotationOffsets(SceneNodeContainer sncAnnotation, UIInput input) { if (input.CircleCanvasPos.x <= _canvasWidth / 2) { //LEFT sncAnnotation.GetComponent <RectTransformComponent>().Anchors = UIElementPosition.GetAnchors(AnchorPos.DOWN_DOWN_LEFT); sncAnnotation.GetComponent <RectTransformComponent>().Offsets = UIElementPosition.CalcOffsets( AnchorPos.DOWN_DOWN_LEFT, input.AnnotationCanvasPos, UIHelper.CanvasHeightInit, UIHelper.CanvasWidthInit, UIHelper.AnnotationDim); } else { //RIGHT sncAnnotation.GetComponent <RectTransformComponent>().Anchors = UIElementPosition.GetAnchors(AnchorPos.DOWN_DOWN_RIGHT); sncAnnotation.GetComponent <RectTransformComponent>().Offsets = UIElementPosition.CalcOffsets( AnchorPos.DOWN_DOWN_RIGHT, input.AnnotationCanvasPos, UIHelper.CanvasHeightInit, UIHelper.CanvasWidthInit, UIHelper.AnnotationDim); } }
private void CalculateNonIntersectingAnnotationPositions(ref UIInput input, ref Dictionary <int, float2> intersectedAnnotations, ref int iterations) { if (!input.IsVisible) { return; } var intersectionCount = 0; for (var i = 0; i < _uiInput.Count; i++) { var counterpart = _uiInput[i]; if (counterpart.Identifier == input.Identifier || !counterpart.IsVisible || intersectedAnnotations.ContainsKey(counterpart.Identifier)) { continue; } var halfAnnotationHeight = (UIHelper.AnnotationDim.y / 2f); var buffer = halfAnnotationHeight - (halfAnnotationHeight / 100f * 10f); //If we do not multiply by the resize scale factor the intersction test will return wrong results because AnnotationCanvasPos is in the range of the size of the initial canvas. var intersect = UIHelper.DoesAnnotationIntersectWithAnnotation(input.AnnotationCanvasPos, _uiInput[i].AnnotationCanvasPos, new float2(0, buffer)); if (!intersect || intersectedAnnotations.ContainsKey(counterpart.Identifier)) { continue; } intersectedAnnotations.Add(counterpart.Identifier, _uiInput[i].AnnotationCanvasPos); intersectionCount++; } if (intersectionCount == 0) { return; } if (intersectedAnnotations.Count >= 1) { if (!intersectedAnnotations.ContainsKey(input.Identifier)) { intersectedAnnotations.Add(input.Identifier, input.AnnotationCanvasPos); //add pos that is just being checked } var orderedBy = intersectedAnnotations.OrderBy(item => item.Value.y).ToList(); intersectedAnnotations = new Dictionary <int, float2>(); foreach (var keyValue in orderedBy) //JSIL not implemented exception: ToDictionary { intersectedAnnotations.Add(keyValue.Key, keyValue.Value); } var middleIndex = (intersectedAnnotations.Count) / 2; var averagePos = new float2(); for (var i = 0; i < intersectedAnnotations.Count; i++) { averagePos += intersectedAnnotations.ElementAt(i).Value; } averagePos /= intersectedAnnotations.Count; for (var i = 0; i < intersectedAnnotations.Count; i++) { var identifier = intersectedAnnotations.ElementAt(i).Key; var thisInput = _uiInput[identifier]; thisInput.AnnotationCanvasPos = averagePos; var multiplier = System.Math.Abs(i - middleIndex); //Distance between annotations is 0.5* AnnotationDim.y if (intersectedAnnotations.Count % 2 == 0) //even { if (i == middleIndex - 1) { thisInput.AnnotationCanvasPos.y -= 0.75f * UIHelper.AnnotationDim.y; } else if (i == middleIndex) { thisInput.AnnotationCanvasPos.y += 0.75f * UIHelper.AnnotationDim.y; } else if (i > middleIndex) { thisInput.AnnotationCanvasPos.y += (0.75f * UIHelper.AnnotationDim.y) + (multiplier * (UIHelper.AnnotationDim.y + UIHelper.AnnotationDim.y / 2)); } else if (i < middleIndex) { thisInput.AnnotationCanvasPos.y -= (0.75f * UIHelper.AnnotationDim.y) + ((multiplier - 1) * (UIHelper.AnnotationDim.y + UIHelper.AnnotationDim.y / 2)); } } else //odd { if (i > middleIndex) { thisInput.AnnotationCanvasPos.y += 0.5f * multiplier * UIHelper.AnnotationDim.y + (UIHelper.AnnotationDim.y * multiplier); } else if (i < middleIndex) { thisInput.AnnotationCanvasPos.y -= 0.5f * multiplier * UIHelper.AnnotationDim.y + (UIHelper.AnnotationDim.y * multiplier); } } _uiInput[identifier] = thisInput; } } //Recursively check all annotations that where involved in this intersection for (var i = 0; i < intersectedAnnotations.Count; i++) { if (i != 0 && i != intersectedAnnotations.Count - 1) { continue; } iterations++; var identifier = intersectedAnnotations.ElementAt(i).Key; var uiInput = _uiInput[identifier]; CalculateNonIntersectingAnnotationPositions(ref uiInput, ref intersectedAnnotations, ref iterations); } }
// Init is called on startup. public override void Init() { if (_canvasRenderMode == CanvasRenderMode.SCREEN) { UIHelper.CanvasWidthInit = Width / 100f; UIHelper.CanvasHeightInit = Height / 100f; } else { UIHelper.CanvasHeightInit = 16; UIHelper.CanvasWidthInit = 9; } _canvasHeight = UIHelper.CanvasHeightInit; _canvasWidth = UIHelper.CanvasWidthInit; _uiInput = new List <UIInput>(); _initWidth = Width; _initHeight = Height; _aspectRatio = Width / (float)Height; //_scene = BuildScene(); _scene = AssetStorage.Get <SceneContainer>("Monkey.fus"); var monkey = _scene.Children[0].GetComponent <Mesh>(); var rnd = new Random(); var numberOfTriangles = monkey.Triangles.Length / 3; var projComp = _scene.Children[0].GetComponent <ProjectionComponent>(); AddResizeDelegate(delegate { projComp.Resize(Width, Height); }); //Create dummy positions on model for (var i = 0; i < NumberOfAnnotations; i++) { var triangleNumber = rnd.Next(1, numberOfTriangles); var triIndex = (triangleNumber - 1) * 3; var triVert0 = monkey.Vertices[monkey.Triangles[triIndex]]; var triVert1 = monkey.Vertices[monkey.Triangles[triIndex + 1]]; var triVert2 = monkey.Vertices[monkey.Triangles[triIndex + 2]]; var middle = (triVert0 + triVert1 + triVert2) / 3; var circleCanvasPos = new float2(middle.x, middle.y); var circleCanvasPosCache = new float2(0, 0); var prob = (float)rnd.NextDouble(); prob = (float)System.Math.Round(prob, 3); var dummyClass = UIHelper.DummySegmentationClasses[rnd.Next(0, UIHelper.DummySegmentationClasses.Count - 1)]; var annotationKind = (UIHelper.AnnotationKind)rnd.Next(0, Enum.GetNames(typeof(UIHelper.AnnotationKind)).Length); var input = new UIInput(annotationKind, middle, new float2(0.65f, 0.65f), dummyClass, prob) { Identifier = i, CircleCanvasPos = circleCanvasPos, CircleCanvasPosCache = circleCanvasPosCache }; input.AffectedTriangles.Add(triIndex); _uiInput.Add(input); } _gui = CreateGui(); // Create the interaction handler _sih = new SceneInteractionHandler(_gui); //Create a scene picker for performing visibility tests _scenePicker = new ScenePicker(_scene); // Set the clear color for the back buffer to white (100% intensity in all color channels R, G, B, A). RC.ClearColor = new float4(0.1f, 0.1f, 0.1f, 1); // Wrap a SceneRenderer around the model. _sceneRenderer = new SceneRenderer(_scene); _guiRenderer = new SceneRenderer(_gui); }
// RenderAFrame is called once a frame public override void RenderAFrame() { // Clear the backbuffer RC.Clear(ClearFlags.Color | ClearFlags.Depth); RC.Viewport(0, 0, Width, Height); #region Controls // Mouse and keyboard movement if (Input.Keyboard.LeftRightAxis != 0 || Input.Keyboard.UpDownAxis != 0) { _keys = true; } if (Input.Mouse.LeftButton) { _keys = false; _angleVelHorz = -RotationSpeed * Input.Mouse.XVel * Time.DeltaTime * 0.0005f; _angleVelVert = -RotationSpeed * Input.Mouse.YVel * Time.DeltaTime * 0.0005f; } else if (Input.Touch.GetTouchActive(TouchPoints.Touchpoint_0)) { _keys = false; float2 touchVel = Input.Touch.GetVelocity(TouchPoints.Touchpoint_0); _angleVelHorz = -RotationSpeed * touchVel.x * Time.DeltaTime * 0.0005f; _angleVelVert = -RotationSpeed * touchVel.y * Time.DeltaTime * 0.0005f; } else { if (_keys) { _angleVelHorz = -RotationSpeed * Input.Keyboard.LeftRightAxis * Time.DeltaTime; _angleVelVert = -RotationSpeed * Input.Keyboard.UpDownAxis * Time.DeltaTime; } else { float curDamp = (float)System.Math.Exp(-Damping * Time.DeltaTime); _angleVelHorz *= curDamp; _angleVelVert *= curDamp; } } _angleHorz += _angleVelHorz; _angleVert += _angleVelVert; // Create the camera matrix and set it as the current ModelView transformation float4x4 mtxRot = float4x4.CreateRotationX(_angleVert) * float4x4.CreateRotationY(_angleHorz); float4x4 mtxCam = float4x4.LookAt(0, 0, -5, 0, 0, 0, 0, 1, 0); float4x4 view = mtxCam * mtxRot; float4x4 perspective = float4x4.CreatePerspectiveFieldOfView(_fovy, (float)Width / Height, ZNear, ZFar); float4x4 orthographic = float4x4.CreateOrthographic(Width, Height, ZNear, ZFar); RC.View = view; RC.Projection = _canvasRenderMode == CanvasRenderMode.Screen ? orthographic : perspective; // Constantly check for interactive objects. if (!Input.Mouse.Desc.Contains("Android")) { _sih.CheckForInteractiveObjects(RC, Input.Mouse.Position, Width, Height); } if (Input.Touch.GetTouchActive(TouchPoints.Touchpoint_0) && !Input.Touch.TwoPoint) { _sih.CheckForInteractiveObjects(RC, Input.Touch.GetPosition(TouchPoints.Touchpoint_0), Width, Height); } #endregion Controls //Annotations will be updated according to circle positions. //Lines will be updated according to circle and annotation positions. RC.View = view; RC.Projection = perspective; SceneNode canvas = _gui.Children[0]; foreach (SceneNode child in canvas.Children) { if (!child.Name.Contains("MarkModelContainer")) { continue; } //1. Calculate the circles canvas position. for (int k = 0; k < child.Children.Count; k++) { SceneNode container = child.Children[k]; SceneNode circle = container.Children[0]; UIInput uiInput = _uiInput[k]; //the monkey's matrices SceneNode monkey = _scene.Children[0]; float4x4 model = monkey.GetGlobalTransformation(); float4x4 projection = perspective; float4x4 mvpMonkey = projection * view * model; float3 clipPos = float4x4.TransformPerspective(mvpMonkey, uiInput.Position); //divides by 2 float2 canvasPosCircle = new float2(clipPos.x, clipPos.y) * 0.5f + 0.5f; canvasPosCircle.x *= _canvasWidth; canvasPosCircle.y *= _canvasHeight; uiInput.CircleCanvasPos = canvasPosCircle; var pos = new float2(uiInput.CircleCanvasPos.x - (uiInput.Size.x / 2), uiInput.CircleCanvasPos.y - (uiInput.Size.y / 2)); //we want the lower left point of the rect that encloses the circle.GetComponent <RectTransform>().Offsets = UIElementPosition.CalcOffsets(AnchorPos.Middle, pos, _canvasHeight, _canvasWidth, uiInput.Size); //1.1 Check if circle is visible PickResult newPick = _scenePicker.Pick(RC, new float2(clipPos.x, clipPos.y)).ToList().OrderBy(pr => pr.ClipPos.z).FirstOrDefault(); if (newPick != null && uiInput.AffectedTriangles[0] == newPick.Triangle) //VISIBLE { uiInput.IsVisible = true; var effect = circle.GetComponent <DefaultSurfaceEffect>(); effect.SetDiffuseAlphaInShaderEffect(UIHelper.alphaVis); } else { uiInput.IsVisible = false; var effect = circle.GetComponent <DefaultSurfaceEffect>(); effect.SetDiffuseAlphaInShaderEffect(UIHelper.alphaInv); } //1.2 Calculate annotation positions without intersections. if (!uiInput.CircleCanvasPos.Equals(uiInput.CircleCanvasPosCache)) { float yPosScale = uiInput.CircleCanvasPos.y / _canvasHeight; yPosScale = (yPosScale - 0.5f) * 2f; uiInput.AnnotationCanvasPos.y = uiInput.CircleCanvasPos.y - (UIHelper.AnnotationDim.y / 2) + (2 * UIHelper.AnnotationDim.y * yPosScale); if (uiInput.CircleCanvasPos.x > _canvasWidth / 2) //RIGHT { uiInput.AnnotationCanvasPos.x = UIHelper.CanvasWidthInit - UIHelper.AnnotationDim.x - UIHelper.AnnotationDistToLeftOrRightEdge; } else { uiInput.AnnotationCanvasPos.x = UIHelper.AnnotationDistToLeftOrRightEdge; } } _uiInput[k] = uiInput; } // 2. Find intersecting annotations and correct their position in _uiInput. // Disable rendering of annotation if its corresponding circle is not visible. for (int k = 0; k < child.Children.Count; k++) { SceneNode container = child.Children[k]; SceneNode annotation = container.Children[1]; UIInput uiInput = _uiInput[k]; if (uiInput.IsVisible) { if (!uiInput.CircleCanvasPos.Equals(uiInput.CircleCanvasPosCache)) { Dictionary <int, float2> intersectedAnnotations = new Dictionary <int, float2>(); int iterations = 0; CalculateNonIntersectingAnnotationPositions(ref uiInput, ref intersectedAnnotations, ref iterations); } annotation.GetComponent <NineSlicePlane>().Active = true; foreach (Mesh comp in annotation.GetComponentsInChildren <Mesh>()) { comp.Active = true; } } else { annotation.GetComponent <NineSlicePlane>().Active = false; foreach (Mesh comp in annotation.GetComponentsInChildren <Mesh>()) { comp.Active = false; } } } // 3. Update annotation positions on canvas and draw line for (int k = 0; k < child.Children.Count; k++) { SceneNode container = child.Children[k]; SceneNode line = container.Children[2]; UIInput uiInput = _uiInput[k]; if (uiInput.IsVisible) { if (!uiInput.CircleCanvasPos.Equals(uiInput.CircleCanvasPosCache)) { UpdateAnnotationOffsets(child.Children[uiInput.Identifier].Children[1], uiInput); DrawLine(child.Children[uiInput.Identifier].Children[2], uiInput); } } DrawLine(line, uiInput); uiInput.CircleCanvasPosCache = uiInput.CircleCanvasPos; _uiInput[k] = uiInput; } } _sceneRenderer.Render(RC); RC.Projection = _canvasRenderMode == CanvasRenderMode.Screen ? orthographic : perspective; _guiRenderer.Render(RC); Present(); }