public void LoadText(SystemLanguage language) { TextAsset textAsset = (TextAsset)Resources.Load(GetResourcePath(language), typeof(TextAsset)); mTextItems = Serialization.DeserialiseFromTextAsset <TextItems>(textAsset); // Add items to dictionary foreach (TextItem item in mTextItems.Items) { if (mTextManagerItems.ContainsKey(item.Id)) { Debug.LogError("TextManager.LoadText - we already have an item with Id " + item.Id); } mTextManagerItems[item.Id] = new List <UsedTextItem>();//new Dictionary<string, bool>(); if (TestCoverage == true) { // text coverage mode. mTextManagerItems[item.Id].Add(new UsedTextItem("xxxxxxxxxxxxxx")); } else { // normal case, just as it used to be foreach (string text in item.GetList()) { mTextManagerItems[item.Id].Add(new UsedTextItem(text)); } } } }
/// <summary> /// Метод для отрисовки расписания /// </summary> private void DrawSchedule() { var machines = (Schedule ?? throw new ArgumentNullException()).Select(m => m.Machine).Distinct().OrderBy(m => m.Name).ToList(); var y = 10; var timeLinePoint = 0; foreach (var machine in machines) { TextItems.Add(new TextDetails(10, y - 35, 50, 50, machine.Name)); RectItems.Add(new RectItem(10, y, 50, 50, "Black")); var batches = Schedule.Where(m => m.Machine.Id == machine.Id).Select(b => b.Batch).ToList(); var x = 65; foreach (var b in batches) { var color = b.NomenclatureId switch { 0 => "Gold", 1 => "Silver", 2 => "LightSteelBlue", _ => "Black" }; timeLinePoint += machine.TimeDictionary[b.NomenclatureId]; var widthFromTime = machine.TimeDictionary[b.NomenclatureId] + 15; TextItems.Add(new TextDetails(x + widthFromTime, y + 32, 20, 20, timeLinePoint.ToString())); TextItems.Add(new TextDetails(x, y, widthFromTime, 20, b.Nomenclature.Name.Substring(0, 3))); RectItems.Add(new RectItem(x, y, widthFromTime, 50, color)); x += widthFromTime + 2; } TimeLines.Add(new TimeLine(10, y + 23, x + 10, y + 23)); y += 90; timeLinePoint = 0; } } }
/// <summary> /// create new SubtitleText from initial string /// </summary> /// <param name="initialText"></param> public SubtitleText(string initialText) : this() { TextItems.Add(initialText); TextDurations.Add(1); doReplace = true; InitFont(); }
public void TextGet() { TestUtils.Upload(c_fileName, c_folderName + "/" + c_fileName); TextItems presentationItems = TestUtils.SlidesApi.GetPresentationTextItems(c_fileName, null, c_password, c_folderName); TextItems presentationItemsWithEmpty = TestUtils.SlidesApi.GetPresentationTextItems(c_fileName, true, c_password, c_folderName); TextItems slideItems = TestUtils.SlidesApi.GetSlideTextItems(c_fileName, c_slideIndex, null, c_password, c_folderName); TextItems slideItemsWithEmpty = TestUtils.SlidesApi.GetSlideTextItems(c_fileName, c_slideIndex, true, c_password, c_folderName); Assert.Less(presentationItems.Items.Count, presentationItemsWithEmpty.Items.Count); Assert.Less(slideItems.Items.Count, presentationItems.Items.Count); Assert.Less(slideItems.Items.Count, slideItemsWithEmpty.Items.Count); }
/// <summary> /// create a new multitext, with multiple strings showing at indicated times. /// </summary> /// <param name="multiText"></param> /// <param name="timings">per multiText item, number of seconds that this item should display</param> /// <param name="doReplace">if true, only latest item from multiText is displayed. /// If false, each item is added to the previous one.</param> public SubtitleText(string[] multiText, float[] timings, bool doReplace) { foreach (var t in multiText) { TextItems.Add(t); } foreach (var t in timings) { TextDurations.Add(t); } this.doReplace = doReplace; InitFont(); }
private void AddTocToHtm() { TextItems.Add(new TextItem { Content = TocCaption, LogicalType = TextItemType.H1 }); foreach (var ti in StructuredText.TextItems) { // ReSharper disable once SwitchStatementMissingSomeCases switch (ti.LogicalType) { case TextItemType.H1: if (TocLevel > 0) { _rowCount++; } break; case TextItemType.H2: if (TocLevel > 1) { _rowCount++; } break; case TextItemType.H3: if (TocLevel > 2) { _rowCount++; } break; case TextItemType.H4: if (TocLevel > 3) { _rowCount++; } break; } } _rowCount++; var row = -1; foreach (var ti in StructuredText.TextItems) { row++; // ReSharper disable once SwitchStatementMissingSomeCases switch (ti.LogicalType) { case TextItemType.H1: if (TocLevel > 0) { //Debug.Print("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n", // ti.Content, _rowCount, // CssToc1); TextItems.Add(new TextItem { Content = string.Format("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n", ti.Content, row + _rowCount + 1, CssToc1), LogicalType = TextItemType.Plain }); } break; case TextItemType.H2: if (TocLevel > 1) { TextItems.Add(new TextItem { Content = string.Format("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n", ti.Content, row + _rowCount + 1, CssToc2), LogicalType = TextItemType.Plain }); } break; case TextItemType.H3: if (TocLevel > 2) { TextItems.Add(new TextItem { Content = string.Format("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n", ti.Content, row + _rowCount + 1, CssToc3), LogicalType = TextItemType.Plain }); } break; case TextItemType.H4: if (TocLevel > 3) { TextItems.Add(new TextItem { Content = string.Format("<p class=\"{2}\"><a href=\"#H{1}\">{0}</a></p>\r\n", ti.Content, row + _rowCount + 1, CssToc4), LogicalType = TextItemType.Plain }); } break; } } foreach (var ti in StructuredText.TextItems) { TextItems.Add(ti); } }
// This article provides a real-world tutorial of how to actually use the API, including // a discussion of many gotchas not identified in the MSDN documentation. // http://www.catch22.net/tuts/uniscribe-mysteries // http://www.catch22.net/tuts/more-uniscribe-mysteries // http://www.catch22.net/tuts/drawing-styled-text-uniscribe // From the developer of Google Chrome's uniscribe client: // https://maxradi.us/documents/uniscribe/ // Arabic embedded (RTL) example: // http://blogs.msdn.com/b/vsarabic/archive/2011/08/21/text-rendering.aspx // Devanagari example: // http://www.omniglot.com/language/articles/devanagari.htm // UTF16 non-zero plane exahere: // https://en.wikipedia.org/wiki/UTF-16#Examples // http://www.i18nguy.com/unicode-example-plane1.html // "Displaying Text with Uniscribe" // https://msdn.microsoft.com/en-us/library/windows/desktop/dd317792%28v=vs.85%29.aspx internal static TextItems AnalyzeText( TextServiceUniscribe service, IntPtr hdc, IntPtr hText, FontRunInfo[] fontRuns) { TextItems o = new TextItems(service); try { o.fontRuns = fontRuns; for (int i = 0; i < fontRuns.Length; i++) { o.count += fontRuns[i].count; o.lineHeight = Math.Max(o.lineHeight, fontRuns[i].fontHeight); } if (o.count == 0) { return o; } int hr; // Lay Out Text Using Uniscribe // 1. Call ScriptRecordDigitSubstitution only when starting or when receiving a WM_SETTINGCHANGE message. // 2. (Optional) Call ScriptIsComplex to determine if the paragraph requires complex processing. hr = ScriptIsComplex( hText, o.count, ScriptIsComplexFlags.SIC_ASCIIDIGIT | ScriptIsComplexFlags.SIC_COMPLEX); if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } // Optional: if S_FALSE (1) is returned, one can fall back to TextRenderer and simplified hit testing // 3. (Optional) If using Uniscribe to handle bidirectional text and/or digit substitution, call // ScriptApplyDigitSubstitution to prepare the SCRIPT_CONTROL and SCRIPT_STATE structures as inputs // to ScriptItemize. If skipping this step, but still requiring digit substitution, substitute // national digits for Unicode U+0030 through U+0039 (European digits). For information about digit // substitution, see Digit Shapes. hr = ScriptApplyDigitSubstitution( IntPtr.Zero, out o.sControl, out o.sState); if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } // 4. Call ScriptItemize to divide the paragraph into items. If not using Uniscribe for digit // substitution and the bidirectional order is known, for example, because of the keyboard layout // used to enter the character, call ScriptItemize. In the call, provide null pointers for the // SCRIPT_CONTROL and SCRIPT_STATE structures. This technique generates items by use of the shaping // engine only, and the items can be reordered using the engine information. // Note: Typically, applications that work only with left-to-right scripts and without any digit // substitution should pass null pointers for the SCRIPT_CONTROL and SCRIPT_STATE structures. { int cMaxItems = 8; SCRIPT_ITEM[] sItems; OPENTYPE_TAG[] sTags; while (true) { sItems = new SCRIPT_ITEM[cMaxItems + 1]; // method adds terminator; sTags = new OPENTYPE_TAG[cMaxItems]; hr = ScriptItemizeOpenType( hText, o.count, cMaxItems, ref o.sControl, ref o.sState, sItems, sTags, out o.cItems); if (hr == E_OUTOFMEMORY) { cMaxItems *= 2; continue; } if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } break; } o.sItems = sItems; o.sTags = sTags; } // 5. Merge the item information with the run information to produce ranges. { int fontRunOffset = 0; int f = 0; int i = 0; while ((f < o.fontRuns.Length) && (i < o.cItems)) { if (fontRunOffset + o.fontRuns[f].count > o.sItems[i + 1].iCharPos) { // run is longer - current item remains intact; advance to next i++; continue; } else if (fontRunOffset + o.fontRuns[f].count < o.sItems[i + 1].iCharPos) { // item too long - split Array.Resize(ref o.sItems, o.cItems + 1 + 1); Array.Copy(o.sItems, i, o.sItems, i + 1, o.sItems.Length - (i + 1)); Array.Resize(ref o.sTags, o.cItems + 1); Array.Copy(o.sTags, i, o.sTags, i + 1, o.sTags.Length - (i + 1)); o.cItems++; o.sItems[i + 1].iCharPos = fontRunOffset + o.fontRuns[f].count; } Debug.Assert(fontRunOffset + o.fontRuns[f].count == o.sItems[i + 1].iCharPos); fontRunOffset += o.fontRuns[f].count; f++; i++; } Debug.Assert(fontRunOffset == o.count); Debug.Assert(o.sItems[o.cItems].iCharPos == o.count); } // 6. Call ScriptShape to identify clusters and generate glyphs. o.sItemsExtra = new ItemInfo[o.cItems]; o.logAttrs = new SCRIPT_LOGATTR[o.count]; for (int i = 0; i < o.cItems; i++) { int start = o.sItems[i].iCharPos; int length = o.sItems[i + 1].iCharPos - start; Font font = null; for (int f = 0, pos = 0; f < o.fontRuns.Length; pos += o.fontRuns[f].count, f++) { font = o.fontRuns[f].font; if (pos < start + length) { break; } } int cMaxGlyphs = (3 * o.count / 2) + 16; // recommended starting value short[] glyphs; short[] logicalClusters; SCRIPT_VISATTR[] visAttrs; // superceded by glyphProps SCRIPT_GLYPHPROP[] glyphProps; int cGlyphs; int fallbackLevel = 0; Font fallbackFont = null; SCRIPT_CHARPROP[] charProps = new SCRIPT_CHARPROP[length]; while (true) { glyphs = new short[cMaxGlyphs]; logicalClusters = new short[cMaxGlyphs]; visAttrs = new SCRIPT_VISATTR[cMaxGlyphs]; glyphProps = new SCRIPT_GLYPHPROP[cMaxGlyphs]; bool needFallback = false; int fontCacheIndex = service.FontCacheIndex(font); GDIFont gdiFont; if (!service.fontToHFont.TryGetValue(font, out gdiFont)) { gdiFont = new GDIFont(font); service.fontToHFont.Add(font, gdiFont); } GDI.SelectObject(hdc, gdiFont); #if false // choose old or OpenType API hr = ScriptShape( hdc, ref service.caches[fontCacheIndex].cache, new IntPtr(hText.ToInt64() + start * 2), length, cMaxGlyphs, ref o.sItems[i].a, glyphs, logicalClusters, visAttrs, out cGlyphs); #else hr = ScriptShapeOpenType( hdc, ref service.caches[fontCacheIndex].cache, ref o.sItems[i].a, o.sTags[i], // tagScript o.sTags[i], // tagLangSys -- right thing to pass here? null, // rcRangeChars null, // rpRangeProperties 0, // cRanges new IntPtr(hText.ToInt64() + start * 2), length, cMaxGlyphs, logicalClusters, charProps, glyphs, glyphProps, // supercedes visAttrs out cGlyphs); #endif if (hr == E_OUTOFMEMORY) { cMaxGlyphs *= 2; glyphs = new short[cMaxGlyphs]; logicalClusters = new short[cMaxGlyphs]; visAttrs = new SCRIPT_VISATTR[cMaxGlyphs]; continue; } if (hr == USP_E_SCRIPT_NOT_IN_FONT) { needFallback = true; goto FontFallback; } if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } // 7. If ScriptShape returns the code USP_E_SCRIPT_NOT_IN_FONT or S_OK with the output containing // missing glyphs, select characters from a different font. Either substitute another font or disable // shaping by setting the eScript member of the SCRIPT_ANALYSIS structure passed to ScriptShape to // SCRIPT_UNDEFINED. For more information, see Using Font Fallback. SCRIPT_FONTPROPERTIES sfp; ScriptGetFontProperties( hdc, ref service.caches[fontCacheIndex].cache, out sfp); for (int j = 0; j < cGlyphs; j++) { if (glyphs[j] == sfp.wgDefault) { needFallback = true; break; } } FontFallback: if (needFallback) { // What worked: // https://code.google.com/p/chromium/codesearch#chromium/src/ui/gfx/font_fallback_win.cc&q=uniscribe&sq=package:chromium&l=283&dr=CSs // http://stackoverflow.com/questions/16828868/how-to-automatically-choose-most-suitable-font-for-different-language // What didn't work: // The totally unhelpful Uniscribe font/script fallback documentation: // https://msdn.microsoft.com/en-us/library/windows/desktop/dd374105%28v=vs.85%29.aspx // MSDN Globalization how-to page about font fallback: // https://msdn.microsoft.com/en-us/goglobal/bb688134.aspx // ScriptShape page: // https://msdn.microsoft.com/en-us/library/windows/desktop/dd368564(v=vs.85).aspx fallbackLevel++; switch (fallbackLevel) { case 1: GDI.LOGFONT fallbackLF; if (GetUniscribeFallbackFont( font, new IntPtr(hText.ToInt64() + 2 * start), length, out fallbackLF)) { fallbackFont = null; foreach (KeyValuePair<GDI.LOGFONT, Font> item in service.fallbackFonts) { if (String.Equals(item.Key.lfFaceName, fallbackLF.lfFaceName) && (item.Key.lfCharSet == fallbackLF.lfCharSet) && (item.Key.lfHeight == fallbackLF.lfHeight)) { fallbackFont = item.Value; break; } } if (fallbackFont == null) { fallbackFont = Font.FromLogFont(fallbackLF); service.fallbackFonts.Add(new KeyValuePair<GDI.LOGFONT, Font>(fallbackLF, fallbackFont)); } font = fallbackFont; continue; } continue; case 2: if (o.sItems[i].a.eScript != SCRIPT_UNDEFINED) { o.sItems[i].a.eScript = SCRIPT_UNDEFINED; } continue; default: // give up break; } } break; } // 8. Call ScriptPlace to generate advance widths and x and y positions for the glyphs in each // successive range. This is the first step for which text size becomes a consideration. int[] iAdvances = new int[cGlyphs]; GOFFSET[] goffsets = new GOFFSET[cGlyphs]; ABC abc = new ABC(); { int fontCacheIndex = service.FontCacheIndex(font); #if false // choose old or OpenType API hr = ScriptPlace( hdc, ref service.caches[fontCacheIndex].cache, glyphs, cGlyphs, visAttrs, ref o.sItems[i].a, iAdvances, goffsets, out abc); #else hr = ScriptPlaceOpenType( hdc, ref service.caches[fontCacheIndex].cache, ref o.sItems[i].a, o.sTags[i], // tagScript o.sTags[i], // tagLangSys -- right thing to pass here? null, // rcRangeChars null, // rpRangeProperties 0, // cRanges new IntPtr(hText.ToInt64() + start * 2), logicalClusters, charProps, length, glyphs, glyphProps, cGlyphs, iAdvances, goffsets, out abc); #endif if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } } o.sItemsExtra[i].glyphs = glyphs; o.sItemsExtra[i].logicalClusters = logicalClusters; o.sItemsExtra[i].visAttrs = visAttrs; o.sItemsExtra[i].cGlyphs = cGlyphs; o.sItemsExtra[i].charProps = charProps; o.sItemsExtra[i].glyphProps = glyphProps; o.sItemsExtra[i].iAdvances = iAdvances; o.sItemsExtra[i].goffsets = goffsets; o.sItemsExtra[i].abc = abc; o.sItemsExtra[i].fallbackFont = fallbackFont; // 9. Sum the range sizes until the line overflows. // 10. Break the range on a word boundary by using the fSoftBreak and fWhiteSpace members in the // logical attributes. To break a single character cluster off the run, use the information returned // by calling ScriptBreak. // Note: Decide if the first code point of a range should be a word break point because the last // character of the previous range requires it. For example, if one range ends in a comma, consider // the first character of the next range to be a word break point. SCRIPT_LOGATTR[] logAttrs1 = new SCRIPT_LOGATTR[o.count]; hr = ScriptBreak( new IntPtr(hText.ToInt64() + 2 * start), length, ref o.sItems[i].a, logAttrs1); if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } Array.Copy(logAttrs1, 0, o.logAttrs, o.sItems[i].iCharPos, length); // 11. Repeat steps 6 through 10 for each line in the paragraph. However, if breaking the last run // on the line, call ScriptShape to reshape the remaining part of the run as the first run on the // next line. } // Display Text Using Uniscribe // 1. For each run, do the following: // a. If the style has changed since the last run, update the handle to the device context by releasing // and getting it again. // b. Call ScriptShape to generate glyphs for the run. // c. Call ScriptPlace to generate an advance width and an x,y offset for each glyph. // 2. Do the following to establish the correct visual order for the runs in the line: // a. Extract an array of bidirectional embedding levels, one per range. The embedding level is // given by (SCRIPT_ITEM) si.(SCRIPT_ANALYSIS) a. (SCRIPT_STATE) s.uBidiLevel. // b. Pass this array to ScriptLayout to generate a map of visual positions to logical positions. byte[] bidiEmbeddingLevels = new byte[o.cItems]; for (int i = 0; i < o.cItems; i++) { bidiEmbeddingLevels[i] = (byte)o.sItems[i].a.s.uBidiLevel; } o.iVisualToLogical = new int[o.cItems]; o.iLogicalToVisual = new int[o.cItems]; hr = ScriptLayout( o.cItems, bidiEmbeddingLevels, o.iVisualToLogical, o.iLogicalToVisual); if (hr < 0) { Marshal.ThrowExceptionForHR(hr); } for (int i = 0; i < o.cItems; i++) { for (int j = 0; j < o.sItemsExtra[i].iAdvances.Length; j++) { o.sItemsExtra[i].totalWidth += o.sItemsExtra[i].iAdvances[j]; } } } catch (Exception) { o.Dispose(); throw; } return o; }
/// <summary> /// Draws the graph /// </summary> private void DrawGraph() { if (CanvasHeight == 0 || CanvasWidth == 0) { return; } //clear the containers RectangleItems.Clear(); LineItems.Clear(); TextItems.Clear(); PointCollection points = new PointCollection(); //set some stuff int numPoints = 100; int ticks = 8; //get the max an min of the efficieny points double maxOrd = EfficiencyMeasurements.Max(e => e.Efficiency); double minOrd = EfficiencyMeasurements.Min(e => e.Efficiency); //get ordinate graph bounds that look nice double ordTickRange = GetTickRange(maxOrd - minOrd, ticks); double ordTickMag = Math.Log10(ordTickRange) > 0 ? Math.Ceiling(Math.Log10(ordTickRange)) : Math.Floor(Math.Log10(ordTickRange)); maxOrd = ordTickRange * Math.Round(1 + maxOrd / ordTickRange); minOrd = ordTickRange * (Math.Round(minOrd / ordTickRange - 1)); double minAbsc = 0;// Properties.Settings.Default.LOWERELIMT * 0.75; double maxAbsc = Properties.Settings.Default.UPPERENERGY; //get abscissa graph bounds that look nice double abscTickRange = GetTickRange(maxAbsc - minAbsc, ticks); double abscTickMag = Math.Log10(abscTickRange) > 0 ? Math.Ceiling(Math.Log10(abscTickRange)) : Math.Floor(Math.Log10(abscTickRange)); maxAbsc = abscTickRange * Math.Round(maxAbsc / abscTickRange); minAbsc = abscTickRange * (Math.Round(minAbsc / abscTickRange)); int seperation = 20; Rectangle chart = new Rectangle(0.2 * CanvasWidth - seperation, seperation, (int)(0.8F * CanvasWidth), (int)(0.8F * CanvasHeight)); //Rectangle chart = new Rectangle(); RectangleItems.Add(chart); //get the energy limit double lowE = minAbsc;// Properties.Settings.Default.LOWERELIMT * 0.75; double highE = maxAbsc; //get the position converstion factors. double xconv = chart.Width / (highE - lowE); double xoff = chart.Right - (xconv * highE); double yconv = chart.Height / (minOrd - maxOrd); double yoff = chart.Bottom - (yconv * minOrd); //build a formatting string StringBuilder format = new StringBuilder("0"); format.Append(ordTickMag >= 0 ? "" : "."); for (int j = 0; j < Math.Abs(ordTickMag); j++) { format.Append(0); } //loop through and add lables int tickLength = 10; double ord = minOrd, absc = minAbsc; while (Math.Round(ord, (int)Math.Abs(ordTickMag)) <= maxOrd) { //draw the y-axis double y;// = (yconv * (ord) + yoff); if (Math.Abs(ord - minOrd) < 1e-6) { y = chart.Bottom - chart.StrokeWeight / 2; } else if (Math.Abs(ord - maxOrd) < 1e-6) { y = chart.Top + chart.StrokeWeight / 2; } else { y = (yconv * (ord) + yoff); LineItems.Add(new Line(chart.Left, y, chart.Right, y) { LineDashArray = { 2, 1 }, }); } LineItems.Add(new Line(chart.Left - tickLength, y, chart.Left + tickLength, y)); //create the label string label = (ord).ToString(format.ToString()); ChartText labelText = new ChartText(label) { //position the label //X = chart.Left - 2 - 0.2*CanvasWidth, X = 0, Y = y + (ordTickRange * yconv) / 2, Width = chart.Left - tickLength - 2, Height = Math.Abs(ordTickRange * yconv), TextHorizontalAlignment = HorizontalAlignment.Right, TextVerticalAlignment = VerticalAlignment.Center }; TextItems.Add(labelText); ord += ordTickRange; } while (Math.Round(absc, (int)Math.Abs(abscTickMag)) <= maxAbsc) { //draw the x-axis double x;// = (xconv * (absc) + xoff); if (Math.Abs(absc - minAbsc) < 1e-6) { x = chart.Left + chart.StrokeWeight / 2; } else if (Math.Abs(absc - maxAbsc) < 1e-6) { x = chart.Right - chart.StrokeWeight / 2; } else { x = (xconv * (absc) + xoff); LineItems.Add(new Line(x, chart.Bottom, x, chart.Top) { LineDashArray = { 2, 1 }, }); } LineItems.Add(new Line(x, chart.Bottom + tickLength, x, chart.Bottom - tickLength)); string label = (absc).ToString(); ChartText labelText = new ChartText(label) { Width = abscTickRange * xconv, Height = 0.2 * CanvasHeight - tickLength - 2 - seperation, //position the label X = x - (abscTickRange * xconv) / 2, Y = chart.Bottom + tickLength + 2, TextHorizontalAlignment = HorizontalAlignment.Center, TextVerticalAlignment = VerticalAlignment.Top }; TextItems.Add(labelText); absc += abscTickRange; } //fill the an array of points that represents the curve double eJump = (highE - lowE) / numPoints; //CurvePoints = new Point[numPoints]; double ene = lowE; for (int i = 0; i < numPoints; i++) { ene += eJump; double eff = data.GetEfficiency(ene); int x = Convert.ToInt32(ene * xconv + xoff); double y = yoff + eff * yconv; if (y > chart.Bottom || double.IsNaN(y)) { y = chart.Bottom; } else if (y < chart.Top || double.IsInfinity(y)) { y = chart.Top; } points.Add(new Point(x, y)); } this.CurvePoints = points; //make the graph thick //put the efficiency points on the chart for (int i = 0; i < EfficiencyMeasurements.Count; i++) { int x = Convert.ToInt32(EfficiencyMeasurements[i].Energy * xconv + xoff); int y = Convert.ToInt32(yoff + EfficiencyMeasurements[i].Efficiency * yconv); int ptSize = 2; RectangleItems.Add(new Rectangle(x - ptSize, y - ptSize, 2 * ptSize, 2 * ptSize)); //add the error bars LineItems.Add(new Line(x, y - EfficiencyMeasurements[i].EfficiencyUncertainty * yconv, x, y + EfficiencyMeasurements[i].EfficiencyUncertainty * yconv)); } WriteEfficiencyEquation(); }