private void renderMultipleThreads(IScannable obj, FillBase fill) { _objectPool.Add(obj); _fillPool.Add(fill); if (!_unlimitedPool && _objectPool.Count == _poolSize) { Flush(); } }
/// <summary> /// Выводит объект. /// </summary> /// <param name="obj">Объект</param> /// <param name="fill">Заливка</param> public void Render(IScannable obj, FillBase fill) { switch (_parallelizationLevel) { case ParallelizationLevel.Single: renderSingleThread(obj, fill); break; case ParallelizationLevel.Duo: case ParallelizationLevel.Quad: renderMultipleThreads(obj, fill); break; } }
private void renderSingleThread(IScannable obj, FillBase fill) { IList <PixelSpan> spans = null; if (obj.BoundingBox.Width >= obj.BoundingBox.Height) { spans = _spanGenerator.GetHorizontalSpans(obj, 0, 0, _rasterData.Width, _rasterData.Height, fill); } else { spans = _spanGenerator.GetVerticalSpans(obj, 0, 0, _rasterData.Width, _rasterData.Height, fill); } foreach (PixelSpan ps in spans) { _rasterData.BlendSpan(ps); } }
private void addSpans(Orientation orientation, List<PixelSpan> spans, List<float[]> pixelScanIntersections, int scanPosition, FillBase fill) { if (pixelScanIntersections.Count == 0) return; float min = float.MaxValue; float max = float.MinValue; foreach (float[] subPixelSpan in pixelScanIntersections) for (int i = 0; i < subPixelSpan.Length; i++) { float spsi = subPixelSpan[i]; if (spsi < min) min = spsi; if (spsi > max) max = spsi; } if (max <= min) return; float[] pixelCoverage = new float[(int)(max + 2) - (int)min]; int shift = (int)min; // вычисление покрытия пикселей foreach (float[] subPixelSpan in pixelScanIntersections) { int subPixelSpanLength = subPixelSpan.Length; if (subPixelSpanLength > 0) { for (int k = 0; k < subPixelSpanLength; k += 2) { float spanStart = subPixelSpan[k]; float spanEnd = subPixelSpan[k + 1]; // длина пересечения сканирующего отрезка с объектом меньше единицы // и это пересечение не пересекает границы пикселей if ((int)spanEnd == (int)spanStart || (int)spanEnd == (int)spanStart + 1) if (spanEnd - spanStart < 1) { pixelCoverage[(int)spanStart - shift] += spanEnd - spanStart; continue; } // пиксели, пересеченные сканирующим отрезком "насквозь" float hv = spanEnd - shift - 1; for (int pixelIndex = (int)spanStart + 1 - shift; pixelIndex < hv; pixelIndex++) pixelCoverage[pixelIndex]++; // пиксель, в котором начался сканирующий отрезок pixelCoverage[(int)spanStart - shift] += 1 - (spanStart - (int)spanStart); // пиксель, в котором закончился сканирующий отрезок if (hv == (int)hv) pixelCoverage[(int)hv] += 1; else pixelCoverage[(int)hv + 1] += spanEnd - (int)spanEnd; } } } // вычисление горизонтальных последовательностей символов int spanStartIndex = 0; bool spanStarted = false; int coverageArrayHiIndex = pixelCoverage.Length - 1; float alphaStep = 255f / _subPixelLevel; for (int i = 0; i <= coverageArrayHiIndex; i++) { if (!spanStarted) { if (pixelCoverage[i] > 0) { spanStartIndex = i; spanStarted = true; } } else { if (pixelCoverage[i] == 0 || i == coverageArrayHiIndex) { Int32[] pixelValues = new int[i - spanStartIndex]; int f = 0; switch(orientation) { case Orientation.Horizontal: for (int k = spanStartIndex; k < i; k++) { double coverage = pixelCoverage[k]; if (coverage > _subPixelLevel) coverage = _subPixelLevel; double antiAliasingAlpha = _alphaTable[(int)(coverage / _subPixelLevel * 254f)]; Int32 color = fill.GetPixelColor((int)min + f + spanStartIndex, scanPosition); byte fillAlpha = (byte)(color >> 24 & 0xFF); if (fillAlpha == 0) pixelValues[f] = (byte)(antiAliasingAlpha * 255f) << 24 | color; else pixelValues[f] = (byte)(antiAliasingAlpha * fillAlpha) << 24 | (color & 0x00FFFFFF); f++; } spans.Add(new PixelSpan(Orientation.Horizontal, (int)min + spanStartIndex, scanPosition, pixelValues)); break; case Orientation.Vertical: for (int k = spanStartIndex; k < i; k++) { double coverage = pixelCoverage[k]; if (coverage > _subPixelLevel) coverage = _subPixelLevel; double antiAliasingAlpha = _alphaTable[(int)(coverage / _subPixelLevel * 254f)]; Int32 color = fill.GetPixelColor(scanPosition, (int)min + f + spanStartIndex); byte fillAlpha = (byte)(color >> 24 & 0xFF); if (fillAlpha == 0) pixelValues[f] = (byte)(antiAliasingAlpha * 255f) << 24 | color; else pixelValues[f] = (byte)(antiAliasingAlpha * fillAlpha) << 24 | (color & 0x00FFFFFF); f++; } spans.Add(new PixelSpan(Orientation.Vertical, scanPosition, (int)min + spanStartIndex, pixelValues)); break; } spanStarted = false; } } } }
/// <summary> /// Возвращает вертикальные последовательности пикселей для /// геометрической фигуры. /// </summary> /// <param name="sourceGeometry"></param> /// <param name="fill">Заливка</param> /// <param name="minX"></param> /// <param name="minY"></param> /// <param name="maxX"></param> /// <param name="maxY"></param> /// <returns>Список вертикальных последовательностей символов</returns> public IList<PixelSpan> GetVerticalSpans(IScannable sourceGeometry, int minX, int minY, int maxX, int maxY, FillBase fill) { List<PixelSpan> spans = new List<PixelSpan>(); BoundingRectangle br = sourceGeometry.BoundingBox; float startY = Math.Max((float)br.MinY, minY); float endY = Math.Min((float)br.MaxY + 1, maxY); float startX = (int)Math.Max((float)br.MinX - 1, minX); float endX = Math.Min((float)br.MaxX + 1, maxX); sourceGeometry.InitScaning((int)startX, (int)endX, minY, maxY, Orientation.Vertical); List<float[]> pixelScanIntersections = new List<float[]>(); for (float scanX = startX; scanX < endX; scanX++) { pixelScanIntersections.Clear(); for (byte i = 0; i < _subPixelLevel; i++) { float[] intersections; sourceGeometry.ComputeVerticalIntersections(scanX + _scanStep * i, out intersections); pixelScanIntersections.Add(intersections); } addSpans(Orientation.Vertical, spans, pixelScanIntersections, (int)scanX, fill); } return spans; }
private void addSpans(Orientation orientation, List <PixelSpan> spans, List <float[]> pixelScanIntersections, int scanPosition, FillBase fill) { if (pixelScanIntersections.Count == 0) { return; } float min = float.MaxValue; float max = float.MinValue; foreach (float[] subPixelSpan in pixelScanIntersections) { for (int i = 0; i < subPixelSpan.Length; i++) { float spsi = subPixelSpan[i]; if (spsi < min) { min = spsi; } if (spsi > max) { max = spsi; } } } if (max <= min) { return; } float[] pixelCoverage = new float[(int)(max + 2) - (int)min]; int shift = (int)min; // вычисление покрытия пикселей foreach (float[] subPixelSpan in pixelScanIntersections) { int subPixelSpanLength = subPixelSpan.Length; if (subPixelSpanLength > 0) { for (int k = 0; k < subPixelSpanLength; k += 2) { float spanStart = subPixelSpan[k]; float spanEnd = subPixelSpan[k + 1]; // длина пересечения сканирующего отрезка с объектом меньше единицы // и это пересечение не пересекает границы пикселей if ((int)spanEnd == (int)spanStart || (int)spanEnd == (int)spanStart + 1) { if (spanEnd - spanStart < 1) { pixelCoverage[(int)spanStart - shift] += spanEnd - spanStart; continue; } } // пиксели, пересеченные сканирующим отрезком "насквозь" float hv = spanEnd - shift - 1; for (int pixelIndex = (int)spanStart + 1 - shift; pixelIndex < hv; pixelIndex++) { pixelCoverage[pixelIndex]++; } // пиксель, в котором начался сканирующий отрезок pixelCoverage[(int)spanStart - shift] += 1 - (spanStart - (int)spanStart); // пиксель, в котором закончился сканирующий отрезок if (hv == (int)hv) { pixelCoverage[(int)hv] += 1; } else { pixelCoverage[(int)hv + 1] += spanEnd - (int)spanEnd; } } } } // вычисление горизонтальных последовательностей символов int spanStartIndex = 0; bool spanStarted = false; int coverageArrayHiIndex = pixelCoverage.Length - 1; float alphaStep = 255f / _subPixelLevel; for (int i = 0; i <= coverageArrayHiIndex; i++) { if (!spanStarted) { if (pixelCoverage[i] > 0) { spanStartIndex = i; spanStarted = true; } } else { if (pixelCoverage[i] == 0 || i == coverageArrayHiIndex) { Int32[] pixelValues = new int[i - spanStartIndex]; int f = 0; switch (orientation) { case Orientation.Horizontal: for (int k = spanStartIndex; k < i; k++) { double coverage = pixelCoverage[k]; if (coverage > _subPixelLevel) { coverage = _subPixelLevel; } double antiAliasingAlpha = _alphaTable[(int)(coverage / _subPixelLevel * 254f)]; Int32 color = fill.GetPixelColor((int)min + f + spanStartIndex, scanPosition); byte fillAlpha = (byte)(color >> 24 & 0xFF); if (fillAlpha == 0) { pixelValues[f] = (byte)(antiAliasingAlpha * 255f) << 24 | color; } else { pixelValues[f] = (byte)(antiAliasingAlpha * fillAlpha) << 24 | (color & 0x00FFFFFF); } f++; } spans.Add(new PixelSpan(Orientation.Horizontal, (int)min + spanStartIndex, scanPosition, pixelValues)); break; case Orientation.Vertical: for (int k = spanStartIndex; k < i; k++) { double coverage = pixelCoverage[k]; if (coverage > _subPixelLevel) { coverage = _subPixelLevel; } double antiAliasingAlpha = _alphaTable[(int)(coverage / _subPixelLevel * 254f)]; Int32 color = fill.GetPixelColor(scanPosition, (int)min + f + spanStartIndex); byte fillAlpha = (byte)(color >> 24 & 0xFF); if (fillAlpha == 0) { pixelValues[f] = (byte)(antiAliasingAlpha * 255f) << 24 | color; } else { pixelValues[f] = (byte)(antiAliasingAlpha * fillAlpha) << 24 | (color & 0x00FFFFFF); } f++; } spans.Add(new PixelSpan(Orientation.Vertical, scanPosition, (int)min + spanStartIndex, pixelValues)); break; } spanStarted = false; } } } }
/// <summary> /// Возвращает вертикальные последовательности пикселей для /// геометрической фигуры. /// </summary> /// <param name="sourceGeometry"></param> /// <param name="fill">Заливка</param> /// <param name="minX"></param> /// <param name="minY"></param> /// <param name="maxX"></param> /// <param name="maxY"></param> /// <returns>Список вертикальных последовательностей символов</returns> public IList <PixelSpan> GetVerticalSpans(IScannable sourceGeometry, int minX, int minY, int maxX, int maxY, FillBase fill) { List <PixelSpan> spans = new List <PixelSpan>(); BoundingRectangle br = sourceGeometry.BoundingBox; float startY = Math.Max((float)br.MinY, minY); float endY = Math.Min((float)br.MaxY + 1, maxY); float startX = (int)Math.Max((float)br.MinX - 1, minX); float endX = Math.Min((float)br.MaxX + 1, maxX); sourceGeometry.InitScaning((int)startX, (int)endX, minY, maxY, Orientation.Vertical); List <float[]> pixelScanIntersections = new List <float[]>(); for (float scanX = startX; scanX < endX; scanX++) { pixelScanIntersections.Clear(); for (byte i = 0; i < _subPixelLevel; i++) { float[] intersections; sourceGeometry.ComputeVerticalIntersections(scanX + _scanStep * i, out intersections); pixelScanIntersections.Add(intersections); } addSpans(Orientation.Vertical, spans, pixelScanIntersections, (int)scanX, fill); } return(spans); }
/// <summary> /// Выводит объект. /// </summary> /// <param name="obj">Объект</param> /// <param name="fill">Заливка</param> public void Render(IScannable obj, FillBase fill) { switch(_parallelizationLevel) { case ParallelizationLevel.Single: renderSingleThread(obj, fill); break; case ParallelizationLevel.Duo: case ParallelizationLevel.Quad: renderMultipleThreads(obj, fill); break; } }
private void renderMultipleThreads(IScannable obj, FillBase fill) { _objectPool.Add(obj); _fillPool.Add(fill); if (!_unlimitedPool && _objectPool.Count == _poolSize) Flush(); }
private void renderSingleThread(IScannable obj, FillBase fill) { IList<PixelSpan> spans = null; if (obj.BoundingBox.Width >= obj.BoundingBox.Height) spans = _spanGenerator.GetHorizontalSpans(obj, 0, 0, _rasterData.Width, _rasterData.Height, fill); else spans = _spanGenerator.GetVerticalSpans(obj, 0, 0, _rasterData.Width, _rasterData.Height, fill); foreach (PixelSpan ps in spans) _rasterData.BlendSpan(ps); }