protected override Dictionary<GloballyFilteredPositionSource, DevicePosition> Reconfigure (
Dictionary<GloballyFilteredPositionSource, DevicePosition> positions)
{
/*
* with world unset, return current positions.
*/
if (World == null) {
return positions;
}
/*
* gather all valid volumes
*/
List<Volume> projectionVolumes = new List<Volume> ();
foreach (Room r in World.GetRooms ()) {
if ("1".Equals (r.GetAttribute (WantDeviceConstant))) {
projectionVolumes.Add (r.Volume);
}
}
/*
* create precomputed distance info
*/
var compositions =
/*
* for each combination...
*/
from src in positions
from target in projectionVolumes
/*
* remove invalid positions
*/
where src.Value != null
/*
* create bunch of info
*/
select new {
Pair = src,
Target = target,
Dist = target.Dist (src.Value.Position),
};
/*
* apply filter
*/
compositions = compositions.Where (x => x.Dist < MaxDist);
/*
* presort
*/
compositions = compositions.OrderBy (x => x.Dist);
/*
* store result
*/
compositions = compositions.ToList ();
/*
* find and store best matches
*/
Dictionary<GloballyFilteredPositionSource, DevicePosition> resultingMatches
= new Dictionary<GloballyFilteredPositionSource, DevicePosition> (positions);
while (compositions.Any ()) {
/*
* find best assignment
*/
var bestMatch = compositions.First ();
/*
* remove used sources and destinations
*/
compositions = compositions.Where (x => x.Pair.Key != bestMatch.Pair.Key);
compositions = compositions.Where (x => x.Target != bestMatch.Target);
compositions = compositions.ToList (); // tested: improves performance
/*
* ultimately add current pair to results
*/
DevicePosition dpResult = new DevicePosition (
bestMatch.Target.Center,
bestMatch.Pair.Value.Time);
resultingMatches[bestMatch.Pair.Key] = dpResult;
}
return resultingMatches;
}
Refactorings
No refactoring yet !
mafutrct
July 9, 2009, July 09, 2009 11:11, permalink
I fooled around with the code some more and this is the result so far.
protected override Dictionary<GloballyFilteredPositionSource, DevicePosition> Reconfigure (
Dictionary<GloballyFilteredPositionSource, DevicePosition> rawPositions)
{
/*
* with world unset, return current positions.
*/
if (World == null) {
return rawPositions;
}
/*
* remove invalid positions
*/
var positions = rawPositions.Where (x => x.Value != null);
/*
* create precomputed distance info
*/
IEnumerable<Composition> compositions = CreateCompositions (positions);
/*
* find and store best matches
*/
var resultingMatches = new Dictionary<GloballyFilteredPositionSource, DevicePosition> ();
foreach (var pos in positions) {
resultingMatches.Add (pos.Key, pos.Value);
}
while (compositions.Any ()) {
/*
* find best assignment
*/
var bestMatch = compositions.First ();
/*
* remove used sources and destinations
*/
compositions = compositions.Where (x => x.Pair.Key != bestMatch.Pair.Key);
compositions = compositions.Where (x => x.Target != bestMatch.Target);
compositions = compositions.ToList (); // tested: improves performance
/*
* ultimately add current pair to results
*/
DevicePosition dpResult = new DevicePosition (
bestMatch.Target.Center,
bestMatch.Pair.Value.Time);
resultingMatches[bestMatch.Pair.Key] = dpResult;
}
return resultingMatches;
}
private List<Composition> CreateCompositions (
IEnumerable<KeyValuePair<GloballyFilteredPositionSource, DevicePosition>> positions)
{
/*
* gather all valid volumes
*/
IEnumerable<Volume> projectionVolumes =
from room in World.GetRooms ()
where "1".Equals (room.GetAttribute (WantDeviceConstant))
select room.Volume;
projectionVolumes = projectionVolumes.ToList ();
/*
* build all pairs
*/
IEnumerable<Composition> compositions =
from src in positions
from target in projectionVolumes
select new Composition (src, target);
/*
* apply filter
*/
compositions = compositions.Where (x => x.Dist < MaxDist);
compositions = compositions.ToList ();
/*
* presort
*/
compositions = compositions.OrderBy (x => x.Dist);
return compositions.ToList ();
}
Diadistis
July 29, 2009, July 29, 2009 15:30, permalink
My take on this
public class Composition
{
public KeyValuePair<GloballyFilteredPositionSource, DevicePosition> Pair { get; set; }
public Room Target { get; set; }
public float Dist { get; set; }
}
...
protected Dictionary<GloballyFilteredPositionSource, DevicePosition> Reconfigure(
Dictionary<GloballyFilteredPositionSource, DevicePosition> positions)
{
// with world unset, return current positions.
if (this.World == null)
{
return positions;
}
// gather all valid volumes
var projectionVolumes =
from r in World.GetRooms()
where r.GetAttribute(WantDeviceConstant).Equals("1")
select r;
// create precomputed distance info
var originalCompositions =
// keep valid positions
from src in positions.Where(x => x.Value != null)
from target in projectionVolumes
// create bunch of info
select new Composition
{
Pair = src,
Target = target,
Dist = target.Dist(src.Value.Position),
};
var finalCompositions = (
from comp in originalCompositions
where comp.Dist < MaxDist // filter
orderby comp.Dist // order
select comp).ToList(); // store as list
var resultingMatches =
new Dictionary<GloballyFilteredPositionSource, DevicePosition>(positions);
while (finalCompositions.Any())
{
// find best assignment
var bestMatch = finalCompositions.First();
// remove used sources and destinations
finalCompositions = (
from comp in finalCompositions
where comp != bestMatch
select comp).ToList();
// add current pair to results
resultingMatches.Add(
bestMatch.Pair.Key,
new DevicePosition(
bestMatch.Target.Center,
bestMatch.Pair.Value.Time));
}
return resultingMatches;
}
A lot of refactoring finally resulted in this long method. I think the code is quite clean and easy to understand. It uses linq a lot, and I'm not really familiar with linq yet, so I figured there are some improvements possible in this area. Also, I'd like to split this method up a bit, so VS does not complain about the admittedly big LOC.