internal static void PullTowardXWithForce(double goalX, PointWithVelocity point, double strength, PedigreeModel model) { double d = goalX - point.x; double force = d * strength; point.dx += force; }
public static void PullTowardY(double goalY, PointWithVelocity point, double strength, PedigreeModel model) { //double distanceFromGoalY = goalY - point.y; //double force = distanceFromGoalY * strength; //point.dy += force; if (!model.pointsBeingDragged.Contains(point)) { point.y = point.y * (1 - strength) + goalY * strength; } }
public static void PullTowardX(double goalX, PointWithVelocity point, double strength, PedigreeModel model) { //double d = goalX - point.x; //double force = d * strength; //point.dx += force; if (!model.pointsBeingDragged.Contains(point)) { point.x = point.x * (1 - strength) + goalX * strength; } }
private static void ShrinkEdge(PedigreeCoupleEdge edge, double strength) { PointWithVelocity a = edge.u.point; PointWithVelocity b = edge.v.point; double distance = b.x - a.x; double forceX = strength * distance; a.dx += forceX; b.dx -= forceX; }
public DragPoints(PedigreeModel model, PedigreeController layoutEngine) { step = delegate() { //if the mouse was pressed and there were no couples being dragged, //drag the one under the mouse point. if (model.io.mousePressed) { double x = model.io.mouseX; // -model.parameters.hOffset; double y = model.io.mouseY; // -model.parameters.vOffset; PointWithVelocity pointUnderCursor = GetPointUnderCursor(model, x, y); if (model.Selected.Count < 2) { if (pointUnderCursor != null) { model.pointsBeingDragged.Add(pointUnderCursor); } } else { bool found = false; foreach (PedigreeIndividual pi in model.Selected) { model.pointsBeingDragged.Add(pi.point); if (pi.point == pointUnderCursor) { found = true; } } if (found == false) { model.pointsBeingDragged.Clear(); } } } if (model.io.mouseReleased) { model.pointsBeingDragged.Clear(); } foreach (PointWithVelocity point in model.pointsBeingDragged) { point.x += ((model.io.mouseX - model.io.pMouseX) / model.parameters.scale); point.y += ((model.io.mouseY - model.io.pMouseY) / model.parameters.scale); } }; }
private static void repelAllCouplePairs(PedigreeModel model) { try { int n = model.couples.Count; //consider the upper triangle (all pairs) for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { PedigreeCouple coupleA = model.couples[i]; PedigreeCouple coupleB = model.couples[j]; if (coupleA.GenerationalLevel == coupleB.GenerationalLevel) { PointWithVelocity a = coupleA.point; PointWithVelocity b = coupleB.point; //separate exactly overlapping points if (b.x - a.x == 0) { a.x += epsilon; } double distance = b.x - a.x; double spread = 200; double forceX = 10 * repulsionStrength * spread / (distance * distance + spread); forceX *= b.x > a.x ? 1 : -1; a.dx -= forceX; b.dx += forceX; } } } } catch (Exception e) { Logger.Instance.WriteToLog(e.ToString()); } }
private static void pullParents(PedigreeModel model, PedigreeCouple couple, bool fatherToLeft) { double halfHSpacing = model.parameters.horizontalSpacing / 2; double reversal = fatherToLeft ? 1 : -1; //position the father to the left { double goalX = couple.point.x - reversal * halfHSpacing; PointWithVelocity point = couple.father.point; double strength = model.parameters.layoutCouplesStrength; PedigreeUtils.PullTowardX(goalX, point, strength, model); } //position the mother to the right { double goalX = couple.point.x + reversal * halfHSpacing; PointWithVelocity point = couple.mother.point; double strength = model.parameters.layoutCouplesStrength; PedigreeUtils.PullTowardX(goalX, point, strength, model); } }
public DetectForceConvergence(PedigreeModel model, PedigreeController layoutEngine) { step = delegate() { if (model.individuals.Count < 2) { layoutEngine.SetMode(PedigreeController.MANUAL); return; } if (model.io.mouseDown == false) { double delta = 0; //bool moving = false; foreach (PedigreeIndividual pi in model.individuals) { double meanX = 0; double meanY = 0; if (model.PositionHistoryX.ContainsKey(pi.HraPerson.relativeID)) { model.PositionHistoryX[pi.HraPerson.relativeID].Add(pi.point.x); if (model.PositionHistoryX[pi.HraPerson.relativeID].Count > model.parameters.PositionHistoryDepth) { model.PositionHistoryX[pi.HraPerson.relativeID].RemoveAt(0); } } else { List <double> past = new List <double>(); past.Add(pi.point.x); model.PositionHistoryX.Add(pi.HraPerson.relativeID, past); } foreach (double cur in model.PositionHistoryX[pi.HraPerson.relativeID]) { meanX += cur; } meanX = meanX / ((double)(model.PositionHistoryX[pi.HraPerson.relativeID].Count)); if (model.PositionHistoryY.ContainsKey(pi.HraPerson.relativeID)) { model.PositionHistoryY[pi.HraPerson.relativeID].Add(pi.point.y); if (model.PositionHistoryY[pi.HraPerson.relativeID].Count > model.parameters.PositionHistoryDepth) { model.PositionHistoryY[pi.HraPerson.relativeID].RemoveAt(0); } } else { List <double> past = new List <double>(); past.Add(pi.point.y); model.PositionHistoryY.Add(pi.HraPerson.relativeID, past); } foreach (double cur in model.PositionHistoryY[pi.HraPerson.relativeID]) { meanY += cur; } meanY = meanY / ((double)(model.PositionHistoryY[pi.HraPerson.relativeID].Count)); if (model.TargetPositions.ContainsKey(pi.HraPerson.relativeID)) { delta += Math.Abs((model.TargetPositions[pi.HraPerson.relativeID].x - meanX)); delta += Math.Abs((model.TargetPositions[pi.HraPerson.relativeID].y - meanY)); model.TargetPositions[pi.HraPerson.relativeID].x = meanX; model.TargetPositions[pi.HraPerson.relativeID].y = meanY; } else { PointWithVelocity pos = new PointWithVelocity(); pos.x = meanX; pos.y = meanY; model.TargetPositions.Add(pi.HraPerson.relativeID, pos); delta += Math.Abs(meanX); delta += Math.Abs(meanY); } } if (delta / model.individuals.Count < 0.05) { if (model.converged == false) { if (layoutEngine.ModelConvergedCallback != null) { layoutEngine.ModelConvergedCallback.Invoke(); } } model.converged = true; } else { model.converged = false; } } }; }
public LayoutCouples(PedigreeModel model) { step = delegate() { if (model.individuals.Count < 2) { return; } double hSpacing = model.parameters.horizontalSpacing; double halfHSpacing = hSpacing / 2; //for each couple, layout the mothers and fathers with no parents foreach (PedigreeCouple couple in model.couples) { if (model.parameters.hideNonBloodRelatives && couple.mother.bloodRelative && !couple.father.bloodRelative) { couple.father.point.x = couple.mother.point.x; couple.point.x = couple.mother.point.x; } else if (model.parameters.hideNonBloodRelatives && couple.father.bloodRelative && !couple.mother.bloodRelative) { couple.mother.point.x = couple.father.point.x; couple.point.x = couple.father.point.x; } else { if (couple.mother != null && couple.father != null) { bool motherHasParents = couple.mother.Parents != null; bool fatherHasParents = couple.father.Parents != null; //if mother and father both have parents, if (motherHasParents && fatherHasParents) { bool fatherToLeft = couple.father.Parents.point.x < couple.mother.Parents.point.x; pullParents(model, couple, fatherToLeft); } //if the mother has parents but the father doesn't, else if (motherHasParents && !fatherHasParents) { //then the mother will be pulled into position by //the layout step for her sibship, so position the //father depending on where the mother is: //pull the father to the left of the mother double goalX = couple.mother.point.x - hSpacing; PointWithVelocity point = couple.father.point; double strength = model.parameters.layoutCouplesStrength; PedigreeUtils.PullTowardX(goalX, point, strength, model); } //if the father has parents but the mother diesn't, else if (!motherHasParents && fatherHasParents) { //then the father will be pulled into position by //the layout step for his sibship, so position the //mother depending on where the father is: //pull the mother to the right of the father double goalX = couple.father.point.x + hSpacing; PointWithVelocity point = couple.mother.point; double strength = model.parameters.layoutCouplesStrength; PedigreeUtils.PullTowardX(goalX, point, strength, model); } //if neither the father nor the mother has parents, else if (!motherHasParents && !fatherHasParents) { //then position them according to their spouse position, //placing the father on the left: { //handle the case of half siblings: bool coupleIsReversed = false; if (couple.mother.spouseCouples.Count == 2) { PedigreeCouple oppositeCouple; if (couple.mother.spouseCouples[0].Equals(couple)) { oppositeCouple = couple.mother.spouseCouples[1]; } else { oppositeCouple = couple.mother.spouseCouples[0]; } double oppositeX = oppositeCouple.point.x; double motherX = couple.point.x; bool oppositeCoupleIsLeftOfMother = oppositeX < motherX; coupleIsReversed = oppositeCoupleIsLeftOfMother; } bool fatherToLeft = !coupleIsReversed; pullParents(model, couple, fatherToLeft); } } } } } }; }
public StaticLayout(PedigreeModel model, PedigreeController layoutEngine) { transitionToStaticLayout = delegate() { if (model.cycles > 1000 || (model.cycles > 800 && model.couplesGraphIsPlanar && model.layoutIsValid == false))// && model.forcesHaveConverged) { //switch modes from self organizing to static if (layoutEngine.GetMode() == PedigreeController.SELF_ORGANIZING) { model.TargetPositions.Clear(); foreach (PedigreeIndividual pi in model.individuals) { PointWithVelocity pos = new PointWithVelocity(); pos.x = pi.point.x; pos.y = pi.point.y; model.TargetPositions.Add(pi.HraPerson.relativeID, pos); } layoutEngine.SetMode(PedigreeController.STATIC_LAYOUT); generations = new List <List <PedigreeIndividual> >(); //initialize the per-level ordering lists for each generation for (int generation = 0; generation <= model.maxGenerationalLevel + 1; generation++) { generations.Add(PedigreeUtils.GetIndividualsInGeneration(model, generation)); } readyToRunStaticLayout = true; } } }; step = delegate() { if (runOnce && readyToRunStaticLayout) { failedAttempts++; readyToRunStaticLayout = false; double spacing = model.parameters.verticalSpacing; double centerY = (model.displayYMin + model.displayYMax) / 2; double offset = centerY - (model.maxGenerationalLevel + 1) * spacing / 2; double initialX = 30; double initialY = centerY; //for each generation, bottom to top... for (int g = generations.Count - 1; g >= 0; g--) //for(int i = 0;i<generations.Count;i++) { List <PedigreeIndividual> generation = generations[g]; //compute the y positions foreach (PedigreeIndividual individual in generation) { individual.point.y = g * spacing + offset; } //for the bottom level, just position with even spaces if (g == generations.Count - 1) { double x = initialX; foreach (PedigreeIndividual individual in generation) { individual.point.x = x += model.parameters.horizontalSpacing; individual.wasMoved = true; } } //for all the other levels... else { //First compute locations of parents centered around their children //and place the parent couples exactly at those centers: //for each individual in the current generation... for (int j = 0; j < generation.Count; j++) { PedigreeIndividual individual = generation[j]; //if the current individual has a spouse... foreach (PedigreeCouple pc in individual.spouseCouples) { //so we compute the center of this couple's sibship, double sibshipCenterX = pc.GetSibshipCenterX(model); //and position the couple such that its center is the same as the sibship center if (pc.father.point.x < pc.mother.point.x) { pc.father.point.x = sibshipCenterX - model.parameters.horizontalSpacing / 2; pc.mother.point.x = sibshipCenterX + model.parameters.horizontalSpacing / 2; } else { pc.mother.point.x = sibshipCenterX - model.parameters.horizontalSpacing / 2; pc.father.point.x = sibshipCenterX + model.parameters.horizontalSpacing / 2; } pc.mother.wasMoved = pc.father.wasMoved = true; } } /**/ //Second, position the outer children: //find the leftmost individual that was placed for (int inc = 1; inc >= -1; inc -= 2) { for (int j = inc == 1 ? 0 : generation.Count - 1; inc == 1 ? j < generation.Count : j >= 0; j += inc) { if (generation[j].wasMoved) { for (int i = j - inc; inc == 1 ? i >= 0 : i < generation.Count; i -= inc) { generation[i].point.x = generation[i + inc].point.x - inc * model.parameters.horizontalSpacing; generation[i].wasMoved = true; } break; } } } //Third, detect "too close"ness and move individuals to be perfectly spaced, //propagating left to right and downward through children for (int j = 0; j < generation.Count - 1; j++) { PedigreeIndividual left = generation[j]; PedigreeIndividual right = generation[j + 1]; //if folks are too close... if (right.point.x - left.point.x < model.parameters.horizontalSpacing) { //move the individual on the right such that spacing is perfect, //based on the current position of the individual on the left double dx = left.point.x + model.parameters.horizontalSpacing - right.point.x; right.point.x += dx; right.wasMoved = true; for (int z = j + 2; z < generation.Count - 1; z++) { PedigreeIndividual farRight = generation[z]; farRight.point.x += dx; farRight.wasMoved = true; } //and through their children foreach (PedigreeCouple pc in left.spouseCouples) { PedigreeIndividual spouse; if (left.HraPerson.relativeID == pc.mother.HraPerson.relativeID) { spouse = pc.father; } else { spouse = pc.mother; } if (right.HraPerson.relativeID == spouse.HraPerson.relativeID) { //PedigreeCouple couple = GetCoupleFromLR(model, left, right); //if (couple != null) MoveChildren(dx, pc, model); } } } } } } for (int g = 0; g < generations.Count - 1; g++) { List <PedigreeIndividual> generation = generations[g]; //for (int j = 0; j < 1; j++) for (int j = generation.Count - 1; j >= 0; j--) { PedigreeIndividual left = generation[j]; if (left.HasSpouse()) { //PedigreeCouple couple = GetCoupleFromLR(model, left, right); foreach (PedigreeCouple pc in model.couples) { double parentsX = (pc.mother.point.x + pc.father.point.x) / 2; if (pc.mother == left || pc.father == left) { double kidsX = 0; foreach (PedigreeIndividual kid in pc.children) { kidsX += kid.point.x; } kidsX = kidsX / ((double)(pc.children.Count)); foreach (PedigreeIndividual kid in pc.children) { kid.point.x += (parentsX - kidsX); foreach (PedigreeCouple kidsPC in kid.spouseCouples) { PedigreeIndividual spouse; if (left.HraPerson.relativeID == pc.mother.HraPerson.relativeID) { spouse = pc.father; } else { spouse = pc.mother; } spouse.point.x += (parentsX - kidsX); spouse.wasMoved = true; } } } } } } } //after positioning everyone, center the pedigree on the screen: double minX = double.MaxValue; double maxX = -minX; foreach (PointWithVelocity point in model.points) { if (point.x < minX) { minX = point.x; } else if (point.x > maxX) { maxX = point.x; } } double centerX = (minX + maxX) / 2; double idealCenterX = (model.displayXMin + model.displayYMax) / 2; double off = idealCenterX - centerX; foreach (PointWithVelocity point in model.points) { point.x = point.x + off; } } //if (LayoutIsValid(model)) if (true) { //model.parameters.repelIndividualSetsStrength = 1; layoutEngine.SetMode(PedigreeController.MANUAL); } //else //{ //layoutEngine.SetMode(PedigreeController.SELF_ORGANIZING); //if (failedAttempts < 5) //{ //model.parameters.repelIndividualSetsStrength += 0.5; //} //else if (failedAttempts < 10) //{ // model.parameters.repelIndividualSetsStrength = 1; // foreach (PointWithVelocity p in model.points) // { // double newX = autoRand.NextDouble() * (model.displayXMax - 1); // double newY = autoRand.NextDouble() * (model.displayYMax - 1); // p.x = newX; // p.dx = 0; // p.y = newY; // p.dy = 0; // } //} //else //{ // layoutEngine.SetMode(PedigreeController.MANUAL); //} /**/ //} }; }
public Pan(PedigreeModel model) { step = delegate() { //if the mouse was pressed and there were no couples being dragged, //drag the one under the mouse point. if (model.io.mousePressed) { double x = model.io.mouseX; double y = model.io.mouseY; PointWithVelocity pointUnderCursor = GetPointUnderCursor(model, x, y); if (pointUnderCursor == null) { x1 = x; y1 = y; hOffset1 = model.parameters.hOffset; vOffset1 = model.parameters.vOffset; panInProgress = true; //model.parameters.multiSelect = true; } } else if (model.io.mouseReleased) { if (model.SelectionLasso.Count > 3) { model.Selected.Clear(); Polygon p = new Polygon(model.SelectionLasso.ToArray()); foreach (PedigreeIndividual pi in model.individuals) { System.Drawing.Point scaled = new System.Drawing.Point((int)pi.point.x, (int)pi.point.y); scaled.X += model.parameters.hOffset; scaled.Y += model.parameters.vOffset; scaled.X = (int)(model.parameters.scale * (double)scaled.X); scaled.Y = (int)(model.parameters.scale * (double)scaled.Y); pi.Selected = false; if (p.Contains(scaled)) { pi.Selected = true; if (model.Selected.Contains(pi) == false) { model.Selected.Add(pi); } } } } else { //PedigreeIndividual s = PedigreeUtils.GetIndividualUnderPoint(model, x1, y1); //if (s != null) //{ // s.Selected = true; // if(model.Selected.Contains(s) == false) // model.Selected.Add(s); //} } model.parameters.multiSelect = false; panInProgress = false; model.SelectionLasso.Clear(); } else if (panInProgress) { double x2 = model.io.mouseX; double y2 = model.io.mouseY; if (model.parameters.multiSelect) { model.SelectionLasso.Add(new System.Drawing.Point((int)x2, (int)y2)); } else { model.parameters.hOffset = (int)(hOffset1 + x2 - x1); model.parameters.vOffset = (int)(vOffset1 + y2 - y1); } } }; }