diff --git a/WordCloudCalculator/Contract/Range.cs b/WordCloudCalculator/Contract/Range.cs index 43cfa13..e7424da 100644 --- a/WordCloudCalculator/Contract/Range.cs +++ b/WordCloudCalculator/Contract/Range.cs @@ -2,25 +2,29 @@ namespace WordCloudCalculator.Contract { - /// - /// Defines Boundaries and provides some related calculation methods - /// - public struct Range - { - private double _min; - private double _max; + /// + /// Defines Boundaries and provides some related calculation methods + /// + public struct Range + { + private double _min; + private double _max; + //private double _step ; - public Range(double min, double max) - { - _max = max; - _min = min; - if(!IsValid) throw new Exception("Invalid Range!"); - } - - /// - /// Lower Bound - /// - public double Min + public Range(double min, double max /*, step = 1.0*/ ) + { + //_step = 1.0; + //_max = Convert.ToInt32(max / _step) * _step; + //_min = Convert.ToInt32(min / _step) * _step; + _max = max; + _min = min; + if (min > max) throw new Exception("Invalid Range!"); + } + //private double InStep(double x, double s) => { return Convert.ToInt32(x / s) * s }; + /// + /// Lower Bound + /// + public double Min { get { return _min; } set @@ -38,7 +42,7 @@ public double Max get { return _max; } set { - if (value < Min) throw new Exception("Maximum cannot be lesser than Minimum!"); + if (!IsValid) throw new Exception("Maximum cannot be lesser than Minimum!"); _max = value; } } @@ -52,10 +56,10 @@ public double Max /// public bool Includes(double value) => Min <= value && value <= Max; - /// - /// Checks if bound relation is correct - /// - public bool IsValid => Max >= Min; + /// + /// Checks if bound relation is correct + /// + public bool IsValid => Max >= Min; /// /// Calculates the relative range value of a given value of an other Range @@ -65,7 +69,7 @@ public double Max /// Relative Range Value public double CalculateRelativeValue(Range valueRange, double currentValue) { - return Min + (currentValue - valueRange.Min)*Amplitude/valueRange.Amplitude; + return Min + (currentValue - valueRange.Min) * Amplitude / valueRange.Amplitude; } } } \ No newline at end of file diff --git a/WordCloudCalculator/Contract/Word/VisualizedWord.cs b/WordCloudCalculator/Contract/Word/VisualizedWord.cs index c798783..594a4ac 100644 --- a/WordCloudCalculator/Contract/Word/VisualizedWord.cs +++ b/WordCloudCalculator/Contract/Word/VisualizedWord.cs @@ -33,6 +33,8 @@ public VisualizedWord(IWord word) /// Defines how strong the word should be displayed [0..1] /// public double Opacity { get; set; } - public override string ToString() => $"{Text}, Position({Position}), FontSize({FontSize}) Opacity = {Opacity:N1}"; - } + public Size Size { get; set; } + public override string ToString() => $"{Text}, Position({Position}), Size({Size}), FontSize({FontSize}) Opacity = {Opacity:N1}"; + + } } \ No newline at end of file diff --git a/WordCloudCalculator/ExtractingWordCloudCalculator/CircleAppearenceCalculationMethod.cs b/WordCloudCalculator/ExtractingWordCloudCalculator/CircleAppearenceCalculationMethod.cs index ea40192..e6066b5 100644 --- a/WordCloudCalculator/ExtractingWordCloudCalculator/CircleAppearenceCalculationMethod.cs +++ b/WordCloudCalculator/ExtractingWordCloudCalculator/CircleAppearenceCalculationMethod.cs @@ -14,86 +14,287 @@ public class CircleAppearenceCalculationMethod : IWordAppearenceCalculationMetho public IWordCloudAppearenceArguments Arguments { get; set; } public double MaxWeight { get; set; } public bool CanAddWords { get; private set; } = true; - public int StopAfterWords { get; set; } = 10; + public int StopAfterWords { get; set; } = 300; + public int Radius { get; set; } = 1; + public int Sectors{ get; set; } = 64; //public List Polygons { get; private set; } - public List Taken { get; private set; } - - public double Area(Rect r) { - return (r.BottomRight - r.BottomLeft) * (r.BottomRight - r.TopRight); + public List Taken { get; private set; } = new List(); + private int Cnt { get; set; } = 0; + private double pos; + + public double CalculateRelativeValue(Range Range, double Weight, double Step, double Multiplier = 1) { + //= Convert.ToInt32((Range.Min / Range.Max * Weight % Range.Max + Range.Min) / Step) * Step, + //var ratio = Range.CalculateRelativeValue(Range, Weight); + var ratio = Range.Min / Range.Max * Weight /*/ (Range.Max - Range.Min)*/; + var i = (ratio % (Range.Max - Range.Min) + Range.Min) ; + var r = Convert.ToInt32(i / Step) * Step; +if(r > Range.Max) + { + ; + } + return r; } +<<<<<<< HEAD + private Point GetSpiralPoint(double position, double radius = 7) { var tau = 2 * Math.PI; double mult = position / tau * radius; double angle = position % tau; return new Point((int)(mult * Math.Sin(angle)), (int)(mult * Math.Cos(angle))); +======= + public double Area(Rect r) { // (Groß-Klein)^2 + if (r.IsEmpty) { return 0; } + return (r.Bottom - r.Top) * (r.Right - r.Left); + } + public bool RectIntersectsRect(Rect r1, Rect r2) { + var p1 = new Point(r1.Left, r1.Top); + var p2 = new Point(r1.Right, r1.Top); + var p3 = new Point(r1.Left, r1.Bottom); + var p4 = new Point(r1.Right, r1.Bottom); + if (PointIntersectsRect(p1, r2)) return true; + if (PointIntersectsRect(p2, r2)) return true; + if (PointIntersectsRect(p3, r2)) return true; + if (PointIntersectsRect(p4, r2)) return true; + return false; + } + public bool PointIntersectsRect(Point p, Rect r2) + { + if ( ( p.Y >= r2.Top && p.Y <= r2.Bottom) && (p.X <= r2.Right && p.X >= r2.Left) ) { + return true; + } + return false; +>>>>>>> origin } - - public VisualizedWord CalculateWordAppearence( IWeightedWord word, int itemIndex/*, VisualizedWord preDecessors*/ ) { + public VisualizedWord CalculateWordAppearence(IWeightedWord word, int itemIndex/*, VisualizedWord preDecessors*/ ) { + //Ausdehnung var size = Arguments.WordSizeCalculator(word.Text, CalculateRelativeValue(Arguments.FontSizeRange, word.Weight)); - var s = new System.Windows.Size(size.Width, size.Height); + var s = new System.Windows.Size(size.Width + Arguments.WordMargin.Left + Arguments.WordMargin.Right, + size.Height+ Arguments.WordMargin.Top + Arguments.WordMargin.Bottom); + //Startpunkt ermitteln var p = new Point(); + if (itemIndex == 0) { //vll auch (0,0), später! - //var p = new Point( - // (Arguments.PanelSize.Width + s.Width) / 2, - // (Arguments.PanelSize.Height + s.Width) / 2 - //); - p.X = (Arguments.PanelSize.Width + s.Width) / 2; - p.Y = (Arguments.PanelSize.Height + s.Width) / 2; + p.X = 0 - Arguments.WordMargin.Left; + p.Y = 0 - Arguments.WordMargin.Top; + pos = 0; } else { - //var p = new Point(); - //p=getpoint() + p = GetSpiralPoint(pos/*, radius = 2*/); + p.X -= Arguments.WordMargin.Left; + p.Y -= Arguments.WordMargin.Top; + } + //mach' ein Rechteck d'raus - var rectangle = new Rect() { + var rectangle = new System.Windows.Rect() { Location = p, Size = s }; + var rectgeom = rectangle;//geometrisch //bis Platz gefunden var found = false; + var nofound = false; + + var offsetvector = new System.Windows.Vector( + Arguments.PanelSize.Width / 2, + Arguments.PanelSize.Height / 2 + ); //Kollisionserkennung: über Vorgänger iterieren //Teste Position (x,y) ist frei für Wort mit Größe size +<<<<<<< HEAD while ( !found ) { if (itemIndex > 0) { //keine Kollision bei 1. Element var intersect = new Rect(); foreach (Rect r in Taken) { intersect = Rect.Intersect(rectangle, r); - if (intersect.IsEmpty) { // darf ich benutzen + if (intersect == System.Windows.Rect.Empty) { // darf ich benutzen found = true; // mit rumschleifen aufhören break; } else { // Platz belegt - // neuen Punkt finden + // neuen Punkt finden + + + Point spiralPoint = GetSpiralPoint(r.Left); + int offsetX = Console.WindowWidth/100; + int offsetY = Console.WindowHeight/100; + var testPoint = new Point((int)(spiralPoint.X + offsetX), (int)(spiralPoint.Y - offsetY)); + + + + + + } +======= + var intersect = new Rect(); + var tau = 2* Math.PI; + var itemCnt = 0; + + rectgeom.Offset(offsetvector); + while ( !((itemIndex <= 0) || found ) ) { + nofound = false; + foreach (Rect r in Taken) { + var f = this.RectIntersectsRect(rectangle, r); + if (f) { // darf ich benutzen, anliegende kanten werden als intersected bewertet + nofound = true; +>>>>>>> origin } + } + if ( nofound + || rectgeom.Left < 0 || rectgeom.Left >= Arguments.PanelSize.Width + || rectgeom.Top < 0 || rectgeom.Top >= Arguments.PanelSize.Height + || rectgeom.Right < 0 || rectgeom.Right >= Arguments.PanelSize.Width + || rectgeom.Bottom < 0 || rectgeom.Bottom >= Arguments.PanelSize.Height + ) { + nofound = true; } +<<<<<<< HEAD + }; //bzw. of Position (x,y) bis Position (x+size.Width,y+size.Height) frei/leer ist //wenn nicht, neue Position anhand Spirale a(r,phi) => a(x,y) + Taken.Add(rectangle); //platzieren +======= + // Platz belegt + // neue Postion anhand Fläche bestimmen, min Schritte von 3,6° +>>>>>>> origin - var visualizedTag = new VisualizedWord(word) { - Position = new Position(p.X, p.Y), - Opacity = CalculateRelativeValue(Arguments.OpacityRange, word.Weight) - }; + if (nofound) { + itemCnt++; + Cnt++; + var a = (this.Area(intersect)/this.Area(rectgeom)); + pos += tau/Sectors + a; + p = GetSpiralPoint(pos);//this.Radius + p.X -= (Arguments.WordMargin.Left ); + p.Y -= (Arguments.WordMargin.Top ); + //rectangle.Width += Arguments.WordMargin.Left + Arguments.WordMargin.Right; + //rectangle.Height += Arguments.WordMargin.Top + Arguments.WordMargin.Bottom; + rectangle.Location=p; + rectgeom = rectangle; + rectgeom.Offset(offsetvector); + //nofound = false; + } else { + found = true; + itemCnt = 0; + if (itemIndex > 44) { + ; + } + } + if (itemCnt > Sectors * 2) { + break; + } + } + + //bzw. of Position (x,y) bis Position (x+size.Width,y+size.Height) frei/leer ist + //wenn nicht, neue Position anhand Spirale a(r,phi) => a(x,y) + + //var durch = 0; + //foreach (Rect r in Taken) + //{ + // Console.Write(durch); + // Console.Write(":"); + // Console.Write(r.TopLeft); + // Console.Write("-"); + // Console.Write(r.TopRight); + // Console.Write("\r\n"); + // durch++; + //}; + + // raise flag to stop new Words + if ( + (StopAfterWords >= 1 && itemIndex >= (StopAfterWords - 1)) + || !this.RectIntersectsRect(rectgeom, new Rect(new Point(0, 0), new System.Windows.Size(Arguments.PanelSize.Width, Arguments.PanelSize.Height))) + ) { + CanAddWords = false; + } //rechtecke für nächsten Durchlauf speichern - Taken.Add( rectangle ); + if (!rectangle.IsEmpty || CanAddWords) { + Taken.Add(rectangle); - if (StopAfterWords > 0 && itemIndex == (StopAfterWords - 1)) { - CanAddWords = false; - } + var vergl = new Range(Arguments.FontSizeRange.Min, Arguments.FontSizeRange.Max/*, 0.5*/).CalculateRelativeValue(Arguments.FontSizeRange, word.Weight); + return new VisualizedWord(word) { + Size = new Contract.Visualization.Size(rectangle.Width, rectangle.Height), + //FontSize = Convert.ToInt32((Arguments.FontSizeRange.Min / Arguments.FontSizeRange.Max * word.Weight % Arguments.FontSizeRange.Max + Arguments.FontSizeRange.Min) / 0.5) * 0.5, + //FontSize = Arguments.FontSizeRange.CalculateRelativeValue(Arguments.FontSizeRange, word.Weight/*, 0.5, 1*/), + FontSize = CalculateRelativeValue(Arguments.FontSizeRange, word.Weight, 0.5, 1), + Position = new Position(rectangle.Top, rectangle.Left), + //Opacity = (Arguments.OpacityRange.Min / Arguments.OpacityRange.Max * word.Weight % 150 + Arguments.OpacityRange.Min) / 150 //CalculateRelativeValue(Arguments.OpacityRange, word.Weight, double Step) + Opacity = this.CalculateRelativeValue(Arguments.OpacityRange, word.Weight, 0.1, 1) + //Opacity = Arguments.OpacityRange.CalculateRelativeValue(Arguments.OpacityRange, word.Weight/*, 0.1, 1*/) + } + ; + } else { return new VisualizedWord(word); } - return visualizedTag; } private double CalculateRelativeValue(Range range, double current) { return range.CalculateRelativeValue(new Range(0, MaxWeight), current); } - } + + private Point GetSpiralPoint(double position, double radius=2) + { + var tau = 2 * Math.PI; + + double mult = position / tau * radius; + double angle = position % tau; + + //Console.Write((int)(mult * Math.Sin(angle))); + //Console.Write((int)(mult * Math.Cos(angle))); + //Console.Write(" /-/ "); + + return new Point((int)(mult * Math.Sin(angle)), (int)(mult * Math.Cos(angle))); + } +/* d3-cloud inspired + * s.a. https://github.com/jasondavies/d3-cloud/blob/master/index.js + */ + private Point archimedeanSpiral(System.Windows.Size size) { + //ohne lambda + var e = size.Width / size.Height; + var r = new Random(); + //var t = new Random() { return this.NextDouble() } < .5 ? 1 : -1; + var t = r.NextDouble() < .5 ? 1 : -1; + //Console.Write("e="); Console.Write(e); Console.Write("//"); + //t /= .1; + return new System.Windows.Point(e * (t /= 10) * Math.Cos(t), t * Math.Sin(t)); + //mit lambda? + //var p = new Point() => { e * (t *= .1) * System.Math.Cos(t), t* System.Math.Sin(t) }; + //oder + //return (t) => { e * ( t *= .1 ) * Math.cos(t), t * Math.sin(t) }; + //return function(t) { + // return [e * (t *= .1) * Math.Cos(t), t * Math.Sin(t)]; + //}; + } + //f = afrch(s) + //f(t) + + //private System.Windows.Point rectangularSpiral(System.Windows.Size size) { + // var dy = 4; + // var dx = dy * size.Width / size.Height; + // var x = 0; + // var y = 0; + // return function(t) { + // var sign = t < 0 ? -1 : 1; + // // See triangular numbers: T_n = n * (n + 1) / 2. + // switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) + // { + // case 0: x += dx; break; + // case 1: y += dy; break; + // case 2: x -= dx; break; + // default: y -= dy; break; + // } + // return [x, y]; + // }; + //} +/* /d3-cloud inspired */ + + + } } \ No newline at end of file diff --git a/WordCloudCalculatorConsoleApplication/Program.cs b/WordCloudCalculatorConsoleApplication/Program.cs index f9eb3ea..b7cb9ea 100644 --- a/WordCloudCalculatorConsoleApplication/Program.cs +++ b/WordCloudCalculatorConsoleApplication/Program.cs @@ -14,43 +14,61 @@ class Program static void Main(string[] args) { - var list = new List - { - new DataRow {Text = "Tag1", Weight = 100}, - new DataRow {Text = "Tag2", Weight = 80}, - new DataRow {Text = "Tag3", Weight = 70}, - new DataRow {Text = "Tag4", Weight = 69}, - new DataRow {Text = "Tag5", Weight = 66}, - new DataRow {Text = "Tag6", Weight = 63}, - new DataRow {Text = "Tag7", Weight = 30}, - new DataRow {Text = "Tag8", Weight = 30}, - new DataRow {Text = "Tag9", Weight = 15}, - new DataRow {Text = "Tag14", Weight = 10}, - new DataRow {Text = "Tag10", Weight = 1}, - new DataRow {Text = "Tag11", Weight = 0} - }; - var calc = new ExtractingWordCloudCalculator(); - //var calc = new ExtractingWordCloudCalculator(); +<<<<<<< HEAD +======= + var list = new List(); + //{ + // new DataRow {Text = "Tag1", Weight = 100}, + // new DataRow {Text = "Tag2", Weight = 80}, + // new DataRow {Text = "Tag3", Weight = 70}, + // new DataRow {Text = "Tag4", Weight = 69}, + // new DataRow {Text = "Tag5", Weight = 66}, + // new DataRow {Text = "Tag6", Weight = 63}, + // new DataRow {Text = "Tag7", Weight = 30}, + // new DataRow {Text = "Tag8", Weight = 30}, + // new DataRow {Text = "Tag9", Weight = 15}, + // new DataRow {Text = "Tag14", Weight = 10}, + // new DataRow {Text = "Tag10", Weight = 1}, + // new DataRow {Text = "Tag11", Weight = 0} + //}; + + int max = 3332; + Random r = new Random(); + for (int i = 0; i < max; ++i) { + list.Add( new DataRow { Text = "Tag" + i, Weight = (100 / ( max % 123 ) * i + 1 ) } ); + } + +>>>>>>> origin + //var calc = new ExtractingWordCloudCalculator(); + var calc = new ExtractingWordCloudCalculator(); var appearenaceArgs = new WordCloudAppearenceArguments() { PanelSize = new Size(Console.WindowWidth, Console.WindowHeight), - FontSizeRange = new Range(0.0, 15.0), - OpacityRange = new Range(0.5, 1.0), - WordMargin = Margin.None, + FontSizeRange = new Range(10, 72.0), + OpacityRange = new Range(0.24, 1.0), + WordMargin = new Margin(0,0,0,0), WordSizeCalculator = GetTextMetrics }; var ret = calc.Calculate(appearenaceArgs, list, row => new WeightedWord {Text = row.Text, Weight = row.Weight}); foreach (var c in ret) - { - Console.CursorLeft = Convert.ToInt32(c.Position.Left); - Console.CursorTop = Convert.ToInt32(c.Position.Top); - Console.ForegroundColor = ConsoleColor.Black + Convert.ToInt32(c.Opacity * 15); - Console.Write(c.Text); - } + { + var lleft = Convert.ToInt32(c.Position.Left + appearenaceArgs.PanelSize.Width / 2); + var ltop = Convert.ToInt32(c.Position.Top + appearenaceArgs.PanelSize.Height / 2); + var lwidth = lleft + c.Size.Width; + var lheight = ltop + c.Size.Height; + if (!(lleft < 0 || lleft > appearenaceArgs.PanelSize.Width || lwidth > appearenaceArgs.PanelSize.Width + || ltop < 0 || ltop > appearenaceArgs.PanelSize.Height || lheight > appearenaceArgs.PanelSize.Height)) { + Console.CursorLeft = lleft; + Console.CursorTop = ltop; + + Console.ForegroundColor = (ConsoleColor.Black + 1 + (int)(15 * c.Opacity % 15)); + Console.Write(c.Text); + } + } Console.ReadLine(); } } diff --git a/WordCloudCalculatorModule b/WordCloudCalculatorModule new file mode 160000 index 0000000..b82d346 --- /dev/null +++ b/WordCloudCalculatorModule @@ -0,0 +1 @@ +Subproject commit b82d3461f193c9bf15d430ab6180488e95eb6ffd