views:

52

answers:

1

I currently was tasked to make a genogram for a family consisting of siblings, parents with aunts and uncles with grandparents and greatgrandparents for only blood relatives. My current algorithm is using recursion. but I am wondering how to do it in non recursive way to make it more efficient. it is programmed in c# using graphics to draw on a bitmap.

Current algorithm for calculating x position, the y position is by getting the generation number.

public void StartCalculatePosition()
{
    // Search the start node (The only node with targetFlg set to true)
    Person start = null;
    foreach (Person p in PersonDic.Values)
    {
        if (start == null) start = p;
        if (p.Targetflg)
        {
            start = p;
            break;
        }
    }

    CalcPositionRecurse(start);

    // Normalize the position (shift all values to positive value)
    // Get the minimum value (must be negative)
    // Then offset the position of all marriage and person with that to make it start from zero
    float minPosition = float.MaxValue;
    foreach (Person p in PersonDic.Values)
    {
        if (minPosition > p.Position)
        {
            minPosition = p.Position;
        }
    }
    if (minPosition < 0)
    {
        foreach (Person p in PersonDic.Values)
        {
            p.Position -= minPosition;
        }
        foreach (Marriage m in MarriageList)
        {
            m.ParentsPosition -= minPosition;
            m.ChildrenPosition -= minPosition;
        }
    }
}

/// <summary>
/// Calculate position of genogram using recursion
/// </summary>
/// <param name="psn"></param>
private void CalcPositionRecurse(Person psn)
{
    // End the recursion
    if (psn.BirthMarriage == null || psn.BirthMarriage.Parents.Count == 0) 
    {
        psn.Position = 0.0f;
        if (psn.BirthMarriage != null) 
        {
            psn.BirthMarriage.ParentsPosition = 0.0f;
            psn.BirthMarriage.ChildrenPosition = 0.0f;
        }

        CalculateSiblingPosition(psn);
        return;
    }

    // Left recurse
    if (psn.Father != null)
    {
        CalcPositionRecurse(psn.Father);
    }

    // Right recurse
    if (psn.Mother != null)
    {
        CalcPositionRecurse(psn.Mother);
    }

    // Merge Position
    if (psn.Father != null && psn.Mother != null)
    {
        AdjustConflict(psn.Father, psn.Mother);
        // Position person in center of parent
        psn.Position = (psn.Father.Position + psn.Mother.Position) / 2;
        psn.BirthMarriage.ParentsPosition = psn.Position;
        psn.BirthMarriage.ChildrenPosition = psn.Position;
    }
    else 
    {
        // Single mom or single dad
        if (psn.Father != null)
        {
            psn.Position = psn.Father.Position;
            psn.BirthMarriage.ParentsPosition = psn.Position;
            psn.BirthMarriage.ChildrenPosition = psn.Position;
        }
        else if (psn.Mother != null)
        {
            psn.Position = psn.Mother.Position;
            psn.BirthMarriage.ParentsPosition = psn.Position;
            psn.BirthMarriage.ChildrenPosition = psn.Position;
        }
        else
        {
            // Should not happen, checking in start of function
        }
    }

    // Arrange the siblings base on my position (left younger, right older)
    CalculateSiblingPosition(psn);
}

private float GetRightBoundaryAncestor(Person psn)
{
    float rPos = psn.Position;

    // Get the rightmost position among siblings
    foreach (Person sibling in psn.Siblings) 
    {
        if (sibling.Position > rPos) 
        {
            rPos = sibling.Position;
        }
    }

    if (psn.Father != null) 
    {
        float rFatherPos = GetRightBoundaryAncestor(psn.Father);
        if (rFatherPos > rPos) 
        {
            rPos = rFatherPos;
        }
    }
    if (psn.Mother != null) {
        float rMotherPos = GetRightBoundaryAncestor(psn.Mother);
        if (rMotherPos > rPos) 
        {
            rPos = rMotherPos;
        }
    }

    return rPos;
}

private float GetLeftBoundaryAncestor(Person psn)
{
    float rPos = psn.Position;

    // Get the rightmost position among siblings
    foreach (Person sibling in psn.Siblings)
    {
        if (sibling.Position < rPos)
        {
            rPos = sibling.Position;
        }
    }

    if (psn.Father != null)
    {
        float rFatherPos = GetLeftBoundaryAncestor(psn.Father);
        if (rFatherPos < rPos)
        {
            rPos = rFatherPos;
        }
    }
    if (psn.Mother != null)
    {
        float rMotherPos = GetLeftBoundaryAncestor(psn.Mother);
        if (rMotherPos < rPos)
        {
            rPos = rMotherPos;
        }
    }

    return rPos;
}

/// <summary>
/// Check if two parent group has conflict and compensate on the conflict
/// </summary>
/// <param name="leftGroup"></param>
/// <param name="rightGroup"></param>
public void AdjustConflict(Person leftGroup, Person rightGroup)
{
    float leftMax = GetRightBoundaryAncestor(leftGroup);
    leftMax += 0.5f;
    float rightMin = GetLeftBoundaryAncestor(rightGroup);
    rightMin -= 0.5f;

    float diff = leftMax - rightMin;
    if (diff > 0.0f)
    {
        float moveHalf = Math.Abs(diff) / 2;
        RecurseMoveAncestor(leftGroup, 0 - moveHalf);
        RecurseMoveAncestor(rightGroup, moveHalf);
    }
}

/// <summary>
/// Recursively move a person and all his/her ancestor
/// </summary>
/// <param name="psn"></param>
/// <param name="moveUnit"></param>
public void RecurseMoveAncestor(Person psn, float moveUnit)
{
    psn.Position += moveUnit;
    foreach (Person siblings in psn.Siblings)
    {
        if (siblings.Id != psn.Id)
        {
            siblings.Position += moveUnit;
        }
    }

    if (psn.BirthMarriage != null)
    {
        psn.BirthMarriage.ChildrenPosition += moveUnit;
        psn.BirthMarriage.ParentsPosition += moveUnit;
    }

    if (psn.Father != null)
    {
        RecurseMoveAncestor(psn.Father, moveUnit);
    }

    if (psn.Mother != null)
    {
        RecurseMoveAncestor(psn.Mother, moveUnit);
    }
}

/// <summary>
/// Calculate the position of the siblings
/// </summary>
/// <param name="psn"></param>
/// <param name="anchor"></param>
public void CalculateSiblingPosition(Person psn)
{
    if (psn.Siblings.Count == 0)
    {
        return;
    }

    List<Person> sibling = psn.Siblings;
    int argidx;
    for (argidx = 0; argidx < sibling.Count; argidx++)
    {
        if (sibling[argidx].Id == psn.Id)
        {
            break;
        }
    }

    // Compute position for each brother that is younger that person
    int idx;
    for (idx = argidx - 1; idx >= 0; idx--)
    {
        sibling[idx].Position = sibling[idx + 1].Position - 1;
    }
    for (idx = argidx + 1; idx < sibling.Count; idx++)
    {
        sibling[idx].Position = sibling[idx - 1].Position + 1;
    }
}
+1  A: 

For converting recursive algorithms to iterative ones Pavel Shved suggested me this link.

TheMachineCharmer