private void computeAndRegisterClusterPoint( LineSegmentCluster clusterEntry, double currValue, HashSet <int> lineSegments) { int nLineSegmentsInSet = lineSegments.Count; Point2D clusterPoint = new Point2D(0, 0); Point2D sweepPoint = new Point2D(0, 0); foreach (int iter in lineSegments) { // get the sweep point of each line segment // this point is parallel to the current value of the sweeping direction sweepPoint = getSweepPointOfLineSegment(clusterEntry, currValue, iter); clusterPoint += sweepPoint / (double)nLineSegmentsInSet; } // NOTE: this program code works only for the 2-dimensional data double x = GET_X_REV_ROTATION(clusterPoint.x, clusterPoint.y, clusterEntry.cosTheta, clusterEntry.sinTheta); double y = GET_Y_REV_ROTATION(clusterPoint.x, clusterPoint.y, clusterEntry.cosTheta, clusterEntry.sinTheta); // register the obtained cluster point (i.e., the average of all the sweep points) clusterEntry.clusterPointArray.Add(new Point2D(x, y)); return; }
private Point2D getSweepPointOfLineSegment(LineSegmentCluster clusterEntry, double currValue, int lineSegmentId) { Segment lineSegmentPoint = m_lineSegmentPointArray[lineSegmentId]; // 2n-dimensional point // NOTE: this program code works only for the 2-dimensional data double newStartX, newEndX, newStartY, newEndY; newStartX = GET_X_ROTATION(lineSegmentPoint.start.x, lineSegmentPoint.start.y, clusterEntry.cosTheta, clusterEntry.sinTheta); newEndX = GET_X_ROTATION(lineSegmentPoint.end.x, lineSegmentPoint.end.y, clusterEntry.cosTheta, clusterEntry.sinTheta); newStartY = GET_Y_ROTATION(lineSegmentPoint.start.x, lineSegmentPoint.start.y, clusterEntry.cosTheta, clusterEntry.sinTheta); newEndY = GET_Y_ROTATION(lineSegmentPoint.end.x, lineSegmentPoint.end.y, clusterEntry.cosTheta, clusterEntry.sinTheta); double coefficient = (currValue - newStartX) / (newEndX - newStartX); return(new Point2D(currValue, newStartY + coefficient * (newEndY - newStartY))); }
private void RegisterAndUpdateLineSegmentCluster(int componentId, int lineSegmentId) { LineSegmentCluster clusterEntry = m_lineSegmentClusters[componentId]; // the start and end values of the first dimension (e.g., the x value in the 2-dimension) // NOTE: this program code works only for the 2-dimensional data Segment aLineSegment = m_lineSegmentPointArray[lineSegmentId]; double orderingValue1 = GET_X_ROTATION(aLineSegment.start.x, aLineSegment.start.y, clusterEntry.cosTheta, clusterEntry.sinTheta); double orderingValue2 = GET_X_ROTATION(aLineSegment.end.x, aLineSegment.end.y, clusterEntry.cosTheta, clusterEntry.sinTheta); CandidateClusterPoint existingCandidatePoint, newCandidatePoint1, newCandidatePoint2; int i, j; // sort the line segment points by the coordinate of the first dimension // simply use the insertion sort algorithm // START ... int iter1 = 0; for (i = 0; i < clusterEntry.candidatePointList.Count; i++) { existingCandidatePoint = clusterEntry.candidatePointList[iter1]; if (existingCandidatePoint.orderingValue >= orderingValue1) { break; } iter1++; } newCandidatePoint1 = new CandidateClusterPoint(); newCandidatePoint1.orderingValue = orderingValue1; newCandidatePoint1.lineSegmentId = lineSegmentId; newCandidatePoint1.startPointFlag = true; if (i == 0) { clusterEntry.candidatePointList.Insert(0, newCandidatePoint1); } else if (i >= clusterEntry.candidatePointList.Count) { clusterEntry.candidatePointList.Add(newCandidatePoint1); } else { clusterEntry.candidatePointList.Insert(iter1, newCandidatePoint1); } int iter2 = 0; for (j = 0; j < clusterEntry.candidatePointList.Count; j++) { existingCandidatePoint = clusterEntry.candidatePointList[iter2]; if (existingCandidatePoint.orderingValue >= orderingValue2) { break; } iter2++; } newCandidatePoint2 = new CandidateClusterPoint(); newCandidatePoint2.orderingValue = orderingValue2; newCandidatePoint2.lineSegmentId = lineSegmentId; newCandidatePoint2.startPointFlag = false; if (j == 0) { clusterEntry.candidatePointList.Insert(0, newCandidatePoint2); } else if (j >= clusterEntry.candidatePointList.Count) { clusterEntry.candidatePointList.Add(newCandidatePoint2); } else { clusterEntry.candidatePointList.Insert(iter2, newCandidatePoint2); } // ... END int trajectoryId = m_idArray[lineSegmentId].trajectoryId; // store the identifier of the trajectories that belong to this line segment cluster if (!clusterEntry.trajectoryIdList.Contains(trajectoryId)) { clusterEntry.trajectoryIdList.Add(trajectoryId); clusterEntry.nTrajectories++; } return; }
private void computeRepresentativeLines(LineSegmentCluster clusterEntry) { HashSet <int> lineSegments = new HashSet <int>(); HashSet <int> insertionList = new HashSet <int>(); HashSet <int> deletionList = new HashSet <int>(); int iter = 0; CandidateClusterPoint candidatePoint, nextCandidatePoint; double prevOrderingValue = 0.0; int nClusterPoints = 0; lineSegments.Clear(); // sweep the line segments in a line segment cluster while (iter != (clusterEntry.candidatePointList.Count - 1) && clusterEntry.candidatePointList.Count > 0) { insertionList.Clear(); deletionList.Clear(); do { candidatePoint = clusterEntry.candidatePointList[iter]; iter++; // check whether this line segment has begun or not if (!lineSegments.Contains(candidatePoint.lineSegmentId)) { // iter1 = lineSegments.find(candidatePoint.lineSegmentId); // if (iter1 == lineSegments.end()) { // if there is no matched element, insertionList.Add(candidatePoint.lineSegmentId); // this line segment begins at this point lineSegments.Add(candidatePoint.lineSegmentId); } else // if there is a matched element, { deletionList.Add(candidatePoint.lineSegmentId); // this line segment ends at this point } // check whether the next line segment begins or ends at the same point if (iter != (clusterEntry.candidatePointList.Count - 1)) { nextCandidatePoint = clusterEntry.candidatePointList[iter]; } else { break; } } while (candidatePoint.orderingValue == nextCandidatePoint.orderingValue); // check if a line segment is connected to another line segment in the same trajectory // if so, delete one of the line segments to remove duplicates foreach (int a in insertionList) { foreach (int b in deletionList) { if (m_idArray[a].trajectoryId == m_idArray[b].trajectoryId) { lineSegments.Remove(b); deletionList.Remove(b); break; } } } // if the current density exceeds a given threshold if (lineSegments.Count >= m_parameter.minLnsParam) { if (Math.Abs(candidatePoint.orderingValue - prevOrderingValue) > ((double)m_parameter.minSegmentLength / 1.414)) { computeAndRegisterClusterPoint(clusterEntry, candidatePoint.orderingValue, lineSegments); prevOrderingValue = candidatePoint.orderingValue; nClusterPoints++; } } // delete the line segment that is not connected to another line segment foreach (int b in deletionList) { lineSegments.Remove(b); } } if (nClusterPoints >= 2) { clusterEntry.nClusterPoints = nClusterPoints; } else { // there is no representative trend in this line segment cluster clusterEntry.enabled = false; clusterEntry.candidatePointList.Clear(); clusterEntry.clusterPointArray.Clear(); clusterEntry.trajectoryIdList.Clear(); } return; }
bool constructLineSegmentCluster() { m_lineSegmentClusters = new LineSegmentCluster[m_currComponentId]; // initialize the list of line segment clusters // START ... for (int i = 0; i < m_currComponentId; i++) { m_lineSegmentClusters[i] = new LineSegmentCluster(); m_lineSegmentClusters[i].avgDirectionVector = new Point2D(0, 0); m_lineSegmentClusters[i].lineSegmentClusterId = i; m_lineSegmentClusters[i].nLineSegments = 0; m_lineSegmentClusters[i].nClusterPoints = 0; m_lineSegmentClusters[i].nTrajectories = 0; m_lineSegmentClusters[i].enabled = false; } // ... END // accumulate the direction vector of a line segment for (int i = 0; i < m_nTotalLineSegments; i++) { int componentId = m_componentIdArray[i]; if (componentId >= 0) { m_lineSegmentClusters[componentId].avgDirectionVector += (m_lineSegmentPointArray[i].end - m_lineSegmentPointArray[i].start); m_lineSegmentClusters[componentId].nLineSegments++; } } // compute the average direction vector of a line segment cluster // START ... double vectorLength1, vectorLength2, innerProduct; double cosTheta, sinTheta; var m_vector2 = new Point2D(1.0, 0.0); for (int i = 0; i < m_currComponentId; i++) { LineSegmentCluster clusterEntry = m_lineSegmentClusters[i]; clusterEntry.avgDirectionVector /= (double)clusterEntry.nLineSegments; vectorLength1 = clusterEntry.avgDirectionVector.Length(); vectorLength2 = 1.0; innerProduct = clusterEntry.avgDirectionVector.Dot(m_vector2); cosTheta = innerProduct / (vectorLength1 * vectorLength2); if (cosTheta > 1.0) { cosTheta = 1.0; } if (cosTheta < -1.0) { cosTheta = -1.0; } sinTheta = Math.Sqrt(1 - Math.Pow(cosTheta, 2)); if (clusterEntry.avgDirectionVector.y < 0) { sinTheta = -sinTheta; } clusterEntry.cosTheta = cosTheta; clusterEntry.sinTheta = sinTheta; } // ... END // summarize the information about line segment clusters // the structure for summarization is as follows // [lineSegmentClusterId, nClusterPoints, clusterPointArray, nTrajectories, { trajectoryId, ... }] for (int i = 0; i < m_nTotalLineSegments; i++) { if (m_componentIdArray[i] >= 0) // if the componentId < 0, it is a noise { RegisterAndUpdateLineSegmentCluster(m_componentIdArray[i], i); } } HashSet <int> trajectories = new HashSet <int>(); for (int i = 0; i < m_currComponentId; i++) { LineSegmentCluster clusterEntry = (m_lineSegmentClusters[i]); // a line segment cluster must have trajectories more than the minimum threshold if (clusterEntry.nTrajectories >= m_parameter.minLnsParam) { clusterEntry.enabled = true; // m_lineSegmentClusters[i].enabled = true; // DEBUG: count the number of trajectories that belong to clusters for (int j = 0; j < clusterEntry.trajectoryIdList.Count; j++) { trajectories.Add(clusterEntry.trajectoryIdList[j]); } computeRepresentativeLines(clusterEntry); // computeRepresentativeLines(m_lineSegmentClusters[i]); } else { clusterEntry.candidatePointList.Clear(); clusterEntry.clusterPointArray.Clear(); clusterEntry.trajectoryIdList.Clear(); } } // DEBUG: compute the ratio of trajectories that belong to clusters m_document.m_clusterRatio = (double)trajectories.Count / (double)m_document.m_trajectoryList.Count; return(true); }