/// <summary> /// Removes duplicate points from the line object /// </summary> private void CleanPoints() { if (linePoints.Any()) { //check if its a point var localIsPoint = linePoints.All(o => o.X == linePoints.First().X&& o.Y == linePoints.First().Y); if (!localIsPoint) { List <Point> newList = new List <Point>(); List <Point> tempList = new List <Point>(); //Since Point is non-nullable, we must ensure the nullPoints, //which we remove can not possibly be points of the original given line. int nullValue = (int)linePoints[0].X + 1; //Fill the gaps between points for (int i = 0; i < linePoints.Count - 1; i++) { nullValue += (int)linePoints[i + 1].X; List <Point> partialList = GeometryCalculator.BresenhamLineAlgorithm(linePoints[i], linePoints[i + 1]); tempList.AddRange(partialList); } Point nullPoint = new Point(nullValue, 0); //Set duplicate points to the null point for (int i = 1; i < tempList.Count; i++) { if ((tempList[i].X == tempList[i - 1].X) && (tempList[i].Y == tempList[i - 1].Y)) { tempList[i - 1] = nullPoint; } } //remove the null points foreach (Point tempPoint in tempList) { if (tempPoint.X != nullValue) { newList.Add(tempPoint); } } linePoints = new List <Point>(newList); } else { isPoint = true; point = linePoints.First(); linePoints.Clear(); linePoints.Add(point); } } }
/// <summary> /// A function that checks the deletion matrixes at a certain point /// and returns all Line ids at that point and in a square around it in a certain range. /// </summary> /// <param name="p">The point around which to check.</param> /// <param name="range">The range around the point. If range is 0, only the point is checked.</param> /// <returns>A List of all lines.</returns> private HashSet <int> CheckDeletionMatrixesAroundPoint(Point p, int range) { HashSet <int> returnSet = new HashSet <int>(); foreach (Point pnt in GeometryCalculator.FilledCircleAlgorithm(p, (int)range)) { if (pnt.X >= 0 && pnt.Y >= 0 && pnt.X < rightImageSize.Width && pnt.Y < rightImageSize.Height) { if (isFilledMatrix[(int)pnt.X, (int)pnt.Y]) { returnSet.UnionWith(linesMatrix[(int)pnt.X, (int)pnt.Y]); } } } return(returnSet); }
/// <summary> /// A function to update the displayed lines in the right canvas. /// </summary> public void UpdateRightLines(List <Tuple <bool, InternalLine> > lines) { foreach (Tuple <bool, InternalLine> tup in lines) { var status = tup.Item1; var line = tup.Item2; if (!rightPolyLines.ContainsKey(line.GetID())) { if (!line.isPoint) { Polyline newLine = new Polyline(); newLine.Points = line.GetPointCollection(); rightPolyLines.Add(line.GetID(), newLine); programView.AddNewLineRight(newLine); } else { Ellipse newPoint = new Ellipse(); rightPolyLines.Add(line.GetID(), newPoint); programView.AddNewPointRight(newPoint, line); } } SetVisibility(rightPolyLines[line.GetID()], status); } //Calculate similarity scores UpdateSimilarityScore(Double.NaN); var templist = lines.Where(tup => tup.Item1).ToList(); if (leftLines.Count > 0) { for (int i = 0; i < leftLines.Count; i++) { if (templist.Count == i) { break; } UpdateSimilarityScore(GeometryCalculator.CalculateSimilarity(templist[i].Item2, leftLines[i])); } } else if (templist.Count > 1) { UpdateSimilarityScore(GeometryCalculator.CalculateSimilarity(templist[templist.Count - 2].Item2, templist[templist.Count - 1].Item2)); } }
/// <summary> /// Method to be called every tick. Updates the current Line, or checks for Lines to delete, depending on the drawing mode. /// </summary> public void Tick() { if (cursorPositions.Count > 0) { previousCursorPosition = cursorPositions.Dequeue(); } else { previousCursorPosition = currentCursorPosition; } if (optitrackAvailable) { SetCurrentFingerPosition(new Point(optiTrackX, optiTrackY)); } if (optiTrackInUse && inDrawingMode && !OptiMovingBack) // optitrack is being used { //outside of drawing zone if (!CheckInsideDrawingZone(optiTrackZ)) { //Check if trackable was in drawing zone last tick & program is in drawing mode-> finish line if (optiTrackInsideDrawingZone && inDrawingMode) { optiTrackInsideDrawingZone = false; FinishCurrentLine(true); } } else //Draw with optitrack, when in drawing zone { //Optitrack wasn't in the drawing zone last tick -> start a new line if (!optiTrackInsideDrawingZone) { optiTrackInsideDrawingZone = true; StartNewLine(); } else { currentLine.Add(currentOptiCursorPosition); } programPresenter.UpdateCurrentLine(currentLine); if (optiTrackZ > WARNING_ZONE_BOUNDARY) { wristband.PushForward(); } else if (optiTrackZ < -1 * WARNING_ZONE_BOUNDARY) { wristband.PushBackward(); } } } else if (!optiTrackInUse && inDrawingMode) { //drawing without optitrack cursorPositions.Enqueue(currentCursorPosition); if (inDrawingMode && programPresenter.IsMousePressed()) { currentLine.Add(currentCursorPosition); //programPresenter.UpdateCurrentLine(currentLine); } } //Deletion mode for optitrack and regular use if (!inDrawingMode) { List <Point> uncheckedPoints = new List <Point>(); if (programPresenter.IsMousePressed() && !optiTrackInUse) //without optitrack { uncheckedPoints = GeometryCalculator.BresenhamLineAlgorithm(previousCursorPosition, currentCursorPosition); } if (optiTrackInUse && CheckInsideDrawingZone(optiTrackZ) && !OptiMovingBack) //with optitrack { uncheckedPoints = GeometryCalculator.BresenhamLineAlgorithm(previousOptiCursorPosition, currentOptiCursorPosition); } foreach (Point currPoint in uncheckedPoints) { HashSet <int> linesToDelete = CheckDeletionMatrixesAroundPoint(currPoint, deletionRadius); if (linesToDelete.Count > 0) { programPresenter.PassLastActionTaken(historyOfActions.AddNewAction(new SketchAction(SketchAction.ActionType.Delete, linesToDelete))); foreach (int lineID in linesToDelete) { rightLineList[lineID] = new Tuple <bool, InternalLine>(false, rightLineList[lineID].Item2); } RepopulateDeletionMatrixes(); programPresenter.UpdateRightLines(rightLineList); } } } }