All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.adobe.fontengine.font.CScan Maven / Gradle / Ivy

The newest version!
/*
 *  File: CScan.java
 * 
 *	ADOBE CONFIDENTIAL
 *	___________________
 *
 *	Copyright 2006 Adobe Systems Incorporated
 *	All Rights Reserved.
 *
 *	NOTICE: All information contained herein is, and remains the property of
 *	Adobe Systems Incorporated and its suppliers, if any. The intellectual
 *	and technical concepts contained herein are proprietary to Adobe Systems
 *	Incorporated and its suppliers and may be covered by U.S. and Foreign
 *	Patents, patents in process, and are protected by trade secret or
 *	copyright law. Dissemination of this information or reproduction of this
 *	material is strictly forbidden unless prior written permission is
 *  obtained from Adobe Systems Incorporated.
 */

/*
 * Adobe Patent and/or Adobe Patent Pending invention included within this file:
 * 
 * Adobe patent application tracking # P002,
 * entitled "Dropout-free center point fill method for displaying characters"
 * inventors: William Paxton and Stephen Schiller
 * Issued US Patent 5,200,740 on April 6, 1993.
 * 
 * Adobe patent application tracking # P006,
 * entitled "Connected-run dropout-free center point fill method for displaying characters"
 * inventors: Micheal Byron and Thomas Malloy
 * Issued US Patent 5,233,336 on August 3, 1993.
 *  
 * Adobe patent application tracking # P010C1
 * entitled "Method for editing character bit maps at small sizes using connected runs"
 * inventors: by Micheal Byron and Thomas Malloy
 * Issued US Patent 5,255,357 on October 19, 1993
 */

package com.adobe.fontengine.font;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

/** Scan conversion by center scan.
 */

public final class CScan implements ScanConverter {
 
  private boolean useOffset;
  private boolean horizontalProximityFill;
  
  private double[] slopesArray;
  
  private CrossBuilder crossBuilder;
  
  private Map/**/ scanLines;
  
  private int firstScanline;
  private int lastScanline;

  private Set/**/ crossesAtXMinima;
  private Set/**/ crossesAtXMaxima;
  
  private Set/**/ contours;
  
  private static final double [] slopesArrayInit
    = {0.0d, -0.0625d, -0.29289d, -0.3660d, -0.434d, -0.5d};
  
  private static int indexOfSlope (double inverseSlope) {
    if (inverseSlope < 0.0d) {
      inverseSlope = -inverseSlope; }
    
    if (inverseSlope > Math.tan (Math.toRadians (52.5))) {
      if (inverseSlope > Math.tan (Math.toRadians (82.5))) {
        return 5; }
      if (inverseSlope > Math.tan (Math.toRadians (67.5))) {
        return 4; }
      return 3; }
    
    else if (inverseSlope < Math.tan (Math.toRadians (7.5))) {
      return 1; }
    
    return 2;
  }

  public CScan (boolean useOffset, double idealWidth, boolean horizontalProximityFill) {
    this.useOffset = useOffset;
    this.horizontalProximityFill = horizontalProximityFill;
    
    this.crossBuilder = new CrossBuilder ();
    crossBuilder.setFlatness (1.0d);
    
    this.slopesArray = null;
    
    if (useOffset) {
      slopesArray = new double [slopesArrayInit.length];
      System.arraycopy (slopesArrayInit, 0, slopesArray, 0, slopesArrayInit.length);
      if (idealWidth > 1.0d) {
        double g = 2 * idealWidth - 1.0d;
        for (int i = 1; i < slopesArray.length; i++) {
          slopesArray [i] = Math.max (slopesArray [i] * g, -1.0d); }}}
  }
   
  private abstract class Cross {
    double x;
    double y;
    Contour contour;
    
    public String toString () {
      return "{" + (Math.round (x * 100) / 100.0d) + ", " + (Math.round (y * 100) / 100.0d) + "}";
    }
  }
  
  private class IntersectionCross extends Cross implements Comparable {
    double xPixel;
    int slopeIndex;
    
    public IntersectionCross (double x, double y) {
      this.x = x;
      this.y = y;
    }
    
    public boolean isLeftInRun () {
      List/**/ scanLine = getScanline ((int) Math.floor (y));
      for (Iterator/**/ it = scanLine.iterator(); it.hasNext(); ) {
        IntersectionCross c = (IntersectionCross) it.next ();
        if (c == this) {
          return true; }
        c = (IntersectionCross) it.next ();
        if (c == this) {
          return false; }}
      throw new RuntimeException ("unpaired crosses in run at y=" + y);
    }
    
    public IntersectionCross leftInRun () {
      List/**/ scanLine = getScanline ((int) Math.floor (y));
      IntersectionCross previous = null;
      for (Iterator/**/ it = scanLine.iterator(); it.hasNext(); ) {
        IntersectionCross c = (IntersectionCross) it.next ();
        if (c == this) {
          return previous; }
        else {
          previous = c; }}
      return null;
    }
    
    public IntersectionCross rightInRun () {
      List/**/ scanLine = getScanline ((int) Math.floor (y));
      for (Iterator/**/ it = scanLine.iterator(); it.hasNext(); ) {
        IntersectionCross c = (IntersectionCross) it.next ();
        if (c == this) {
          if (it.hasNext ()) {
            return (IntersectionCross) it.next (); }
          else {
            return null; }}}
      return null;
    }
   
    public int compareTo (Object arg0) {
      IntersectionCross e = (IntersectionCross) arg0;
      if (e.x < x) {
        return +1; }
      else if (e.x == x) {
        return 0; }
      else {
        return -1; }
    }  
  }
  
  private class ExtraCross extends Cross {

    public ExtraCross (double x, double y) {
      this.x = x;
      this.y = y;
    }
  }

  private class CrossBuilder extends OutlineConsumer2BaseImpl {
    
    private double THRESHOLD = 127.0;
    private double epsilon;
    
    public void setFlatness (double flatness) {
       epsilon = Math.max (1.0d/8192, 1.5d * flatness / 4);
    }

    //--------------------------------------------------------------------------
    
    public void startOutline () {
      scanLines = new HashMap ();
      
      firstScanline = Integer.MAX_VALUE;
      lastScanline = Integer.MIN_VALUE;

      crossesAtXMinima = new HashSet ();
      crossesAtXMaxima = new HashSet ();
      
      contours = new HashSet ();
    }
    
    public void startContour () {
      contour = new Contour ();
      vertDir = NO_DIR;
      horizDir = NO_DIR;
    }

    public void line (double x1, double y1, double x2, double y2) {
      /* Make sure we never have a point on a midline */
      if (Math.abs(y1 - Math.floor (y1) - 0.5d) < 0.00001) {
        y1 += y1/1000.0; }
      if (Math.abs(y2 - Math.floor (y2) - 0.5d) < 0.00001) {
        y2 += y2/1000.0; }
      
      if (horizDir == NO_DIR) {
        firstSegmentX1 = x1;
        firstSegmentY1 = y1;
        firstSegmentX2 = x2;
        firstSegmentY2 = y2;
        setDirections (x1, y1, x2, y2); }
      else {
        addInflectionCrossIfNeeded (x1, y1, x2, y2); }
      
      if (y1 < y2) {
        double inversedSlope = (x2 - x1) / (y2 - y1);
        double yMid = Math.floor (y1 + 0.5) + 0.5;
        double xMid = x1 + (yMid - y1) * inversedSlope;       
        while (yMid <= y2) {
          IntersectionCross c = new IntersectionCross (xMid, yMid); 
          if (useOffset) {
            c.slopeIndex = indexOfSlope (inversedSlope); }
          addIntersectionCross (c);
          yMid += 1.0;
          xMid += inversedSlope; }}
      
      else if (y2 < y1) {
        double inversedSlope = (x2 - x1) / (y2 - y1);
        double yMid = Math.floor (y1 - 0.5) + 0.5; /* round down to a pixel midline */
        double xMid = x1 + (yMid - y1) * inversedSlope;
        while (y2 <= yMid) {
          IntersectionCross c = new IntersectionCross (xMid, yMid); 
          if (useOffset) {
            c.slopeIndex = indexOfSlope (inversedSlope); }
          addIntersectionCross (c);
          yMid -= 1.0;
          xMid -= inversedSlope; }}
    }

    public void quadraticCurve (double x1, double y1,
                                double x2, double y2, 
                                double x3, double y3) {
      if (   (   (x1 <= x2 && x2 <= x3)
              || (x3 <= x2 && x2 <= x1))
          && (Math.abs (x3 - x1) < THRESHOLD)
          && (Math.abs ((x3 - x1) - 2 * (x2 - x1)) <= epsilon)
          && (   (y1 <= y2 && y2 <= y3)
              || (y3 <= y2 && y2 <= y1))
          && (Math.abs (y3 - y1) < THRESHOLD)
          && (Math.abs ((y3 - y1) - 2 * (y2 - y1)) <= epsilon)) {
    
        line (x1, y1, x3, y3); }
      
      else {
        double x12 = (x2 + x1) / 2.0;     double y12 = (y2 + y1) / 2.0;
        double x23 = (x3 + x2) / 2.0;     double y23 = (y3 + y2) / 2.0;
        double x1223 = (x12 + x23) / 2.0; double y1223 = (y12 + y23) / 2.0;
        
        quadraticCurve (x1, y1, x12, y12, x1223, y1223);
        quadraticCurve (x1223, y1223, x23, y23, x3, y3); }
    }

    public void cubicCurve (double x1, double y1, 
                            double x2, double y2, 
                            double x3, double y3, 
                            double x4, double y4) {
      if (   (   (x1 <= x2 && x2 <= x3 && x3 <= x4)
              || (x4 <= x3 && x3 <= x2 && x2 <= x1))
          && (Math.abs (x4 - x1) < THRESHOLD)
          && (Math.abs ((x4 - x1) - 3 * (x2 - x1)) <= epsilon)
          && (Math.abs ((x4 - x1) - 3 * (x4 - x3)) <= epsilon)
          && (   (y1 <= y2 && y2 <= y3 && y3 <= y4)
              || (y4 <= y3 && y3 <= y2 && y2 <= y1))
          && (Math.abs (y4 - y1) < THRESHOLD)
          && (Math.abs ((y4 - y1) - 3 * (y2 - y1)) <= epsilon)
          && (Math.abs ((y4 - y1) - 3 * (y4 - y3)) <= epsilon)) {
        
        line (x1, y1, x4, y4); }
      
      else {
        double x12 = (x2 + x1) / 2.0; double y12 = (y2 + y1) / 2.0;
        double x23 = (x3 + x2) / 2.0; double y23 = (y3 + y2) / 2.0;
        double x34 = (x4 + x3) / 2.0; double y34 = (y4 + y3) / 2.0;
        
        double x1223 = (x23 + x12) / 2.0; double y1223 = (y23 + y12) / 2.0;
        double x2334 = (x34 + x23) / 2.0; double y2334 = (y34 + y23) / 2.0;
        
        double xx = (x1223 + x2334) / 2.0; double yy = (y1223 + y2334) / 2.0;
        
        cubicCurve (x1, y1, x12, y12, x1223, y1223, xx, yy);       
        cubicCurve (xx, yy, x2334, y2334, x34, y34, x4, y4); }
    }
    
    public void endContour () {      
      addInflectionCrossIfNeeded (firstSegmentX1, firstSegmentY1,
                                  firstSegmentX2, firstSegmentY2);
      
      contours.add (contour);
      contour = null;         
    }
    
    public void endOutline () {
    }
    
    //--------------------------------------------------------------------------
    
    final static private int NO_DIR = 0;
    
    final static private int RIGHT_DIR = 1;
    final static private int LEFT_DIR = -1;
    final static private int VERT_DIR = 2;
    
    final static private int UP_DIR = 1;
    final static private int DOWN_DIR = -1;
    final static private int HORIZ_DIR = 2;
    
    private int vertDir;
    private int horizDir;
    
    private Contour contour;

    private double firstSegmentX1;
    private double firstSegmentY1;
    private double firstSegmentX2;
    private double firstSegmentY2;
    
    private void setDirections (double x1, double y1, double x2, double y2) {
      if (x1 < x2) {
        horizDir = RIGHT_DIR; }
      
      else if (x1 == x2) {
        horizDir = VERT_DIR; }
      
      else /* (x1 > x2) */ {
        horizDir = LEFT_DIR; }
      
      
      if (y1 < y2) {
        vertDir = UP_DIR; }

      else if (y1 == y2) {
        vertDir = HORIZ_DIR; }
      
      else /* (y1 > y2) */ {
          vertDir = DOWN_DIR; } 
    }
    
    private void addInflectionCrossIfNeeded (double x1, double y1, double x2, double y2) {
      boolean allPoints = false;
      Cross c = null;

      if (allPoints) {
        c = new ExtraCross (x1, y1); }
      
      if (x1 < x2 && horizDir != RIGHT_DIR) {
        if (horizDir != NO_DIR) {
          if (c == null) {
            c = new ExtraCross (x1, y1); }
          crossesAtXMinima.add (c); }
        horizDir = RIGHT_DIR; }
      
      else if (x1 == x2 && horizDir != VERT_DIR) {
        if (horizDir != NO_DIR) {
          if (c == null) {
            c = new ExtraCross (x1, y1); }
          if (horizDir == LEFT_DIR) {
            crossesAtXMinima.add (c); }
          else {
            crossesAtXMaxima.add (c); }}
        horizDir = VERT_DIR; }
      
      else if (x1 > x2 && horizDir != LEFT_DIR) {
        if (horizDir != NO_DIR) {
          if (c == null) {
            c = new ExtraCross (x1, y1); }
          crossesAtXMaxima.add (c); }
        horizDir = LEFT_DIR; }
      
      if (y1 < y2) {
        if (vertDir != UP_DIR) {
          if (c == null) {
            c = new ExtraCross (x1, y1); }
          vertDir = UP_DIR; }}

      else if (y1 == y2) {
        if (vertDir != HORIZ_DIR) {
          if (c == null) {
            c = new ExtraCross (x1, y1); }
          vertDir = HORIZ_DIR; }}
      
      else {
        if (vertDir != DOWN_DIR) { 
          if (c == null) {
            c = new ExtraCross (x1, y1); }
          vertDir = DOWN_DIR; }}
      
      if (c != null) {
        addCrossToCountour (c); }    
    }
    
    
    private void addIntersectionCross (IntersectionCross c) {
      int y = (int) Math.floor (c.y);
      firstScanline = Math.min (firstScanline, y);
      lastScanline = Math.max (lastScanline, y);
      
      Integer Y = new Integer (y); 
      LinkedList/**/ l = (LinkedList/**/) scanLines.get (Y);
      if (l == null) {
        l = new LinkedList/**/ ();
        scanLines.put (Y, l);}
      
      ListIterator it = l.listIterator();
      
      if (!it.hasNext()) {
    	  l.add(0, c); }
      else {
    	  boolean added = false;
	      for (; it.hasNext();){
	    	  IntersectionCross cross = (IntersectionCross)it.next();
	    	  if (cross.compareTo(c) >= 0) {
	    		  if (it.hasPrevious()) {
		    		  it.previous();
		    		  it.add (c); }
	    		  else {
	    			  l.add(0, c);
	    		  }
	    		  added = true;
	    		  break; }
	      }
	      if (!added)
	    	  l.add(c);
      }
      
      addCrossToCountour (c);
    }
    
    private void addCrossToCountour (Cross c) {
      c.contour = contour;
      contour.add (c);
    }
  }
  

  private class Contour {
    private static final int FORWARD = 1;
    private static final int BACKWARD = -1;
       
    private List/**/ crosses = new ArrayList/**/ ();
    
    public void add (Cross c) {
      crosses.add (c);
    }
      
    public IntersectionCross intersectionCrossBefore (Cross c1) {
      return adjacentIntersectionCross (c1, BACKWARD);
    }
    
    public IntersectionCross intersectionCrossAfter (Cross c1) {
      return adjacentIntersectionCross (c1, FORWARD);
    }
    
    public Cross adjacentCross (Cross c1, int direction) {
      int i = crosses.indexOf (c1);
      i = (i + direction) % crosses.size();
      if (i < 0) { i = i + crosses.size(); }
      return (Cross) crosses.get (i);
    }
    
    public IntersectionCross adjacentIntersectionCross (Cross c1, int direction) {
      Cross c2;
      
      int i = crosses.indexOf (c1);
      do {
        i = (i + direction) % crosses.size ();
        if (i < 0) { i = i + crosses.size (); }
        c2 = (Cross) crosses.get (i); } 
      while (! (c2 instanceof IntersectionCross) && (c2 != c1));
      if (c2 instanceof IntersectionCross) {
        return (IntersectionCross) c2; }
      else {
        return null; }
    }

    public Iterator/**/ iterator () {
      return crosses.iterator();
    }
    
    public class IntersectionEdgeIterator {
      int cursor = 0;
      IntersectionCross first;
      IntersectionCross second;

      public IntersectionEdgeIterator () {
        while (cursor < crosses.size () && ! (crosses.get (cursor) instanceof IntersectionCross)) {
          cursor++; }
      }
      
      public boolean hasNext () {
        return cursor < crosses.size ();
      }

      public void next () {
        first = (IntersectionCross) crosses.get (cursor);
        int o = (cursor + 1) % crosses.size ();
        while (! (crosses.get (o) instanceof IntersectionCross)) {
          o = (o + 1) % crosses.size (); }
        second = (IntersectionCross) crosses.get (o);
        
        cursor++;
        while (cursor < crosses.size () && ! (crosses.get (cursor) instanceof IntersectionCross)) {
          cursor++; }
      }
      
      public IntersectionCross c1 () {
        return first;

      }
      public IntersectionCross c2 () {
        return second;
      }
    }
    
    public IntersectionEdgeIterator iterateIntersectionEdges () {
      return new IntersectionEdgeIterator ();
    }
    
    public class EdgeIterator {
      int cursor = 0;
      int limit;
      boolean forceHas;
      
      Cross first;
      Cross second;
      
      public EdgeIterator (Cross c1, Cross c2) {
        cursor = crosses.indexOf (c1);
        limit = crosses.indexOf (c2);
        forceHas = false;
      }
      
      public EdgeIterator () {
        cursor = 0;
        limit = 0;
        forceHas = true;
      }
      
      public boolean hasNext () {
        return (forceHas || cursor != limit);
      }

      public void next () {
        forceHas = false;
        first = (Cross) crosses.get (cursor);
        cursor = (cursor + 1) % crosses.size ();
        second = (Cross) crosses.get (cursor);
      }
      
      public Cross c1 () {
        return first;

      }
      public Cross c2 () {
        return second;
      }
    }
    
    public EdgeIterator iterateEdges (Cross c1, Cross c2) {
      return new EdgeIterator (c1, c2);
    }
    
    public EdgeIterator iterateEdges () {
      return new EdgeIterator ();
    }
  }


  public void setScanType (int scanType) {
    // nothing
  }
  
  public OutlineConsumer2 getOutlineConsumer2 () {
    return crossBuilder;
  }
  
  public void getBitmap (BitmapConsumer bitmapConsumer) {  
    if (ScalerDebugger.debugOn && outlineDebugger != null) {
      paintCrosses (true); }
    
    buildInitialRuns ();
    
    //fillDropouts ();
    editWhiteSpace ();
    returnBits (bitmapConsumer);
  }
  
  private void buildInitialRuns () {
    for (int y = firstScanline; y <= lastScanline; y++) {
      List/**/ crosses = getScanline (y);

      for (Iterator it = crosses.iterator(); it.hasNext (); ) {
        double lastX = Double.NEGATIVE_INFINITY;
        IntersectionCross c1 = (IntersectionCross) it.next ();
        IntersectionCross c2 = (IntersectionCross) it.next ();
        
        if (useOffset) {
          double delta1 = slopesArray [c1.slopeIndex];
          double delta2 = slopesArray [c2.slopeIndex];
          /* we are bringing them closer proportional to the slope of
           * the segments...makes it more likely for the stem
           * to get thinner or shift right (if they are already thin) in
           * correspondence with our narrow stdHW
           */
          c1.x -= delta1;
          c2.x += delta2;
          /* we switched the order...fix that and make stems 1 apart */
          if (c1.x >= c2.x) {
            c1.x = (c1.x + delta1 + c2.x - delta2) / 2;
            c2.x = c1.x + 1; }}
        
        if (c1.x <= lastX) {
          c1.x = lastX + lastX/1000.0;
          c2.x = c1.x + c1.x/1000.0; }
        
        double leftRun = Math.round (c1.x);
        double rightRun = Math.round (c2.x);
        
        if (leftRun != rightRun) {        /* Run crosses at least one vertical midline */
          c1.xPixel = leftRun;
          c2.xPixel = rightRun; }
        
        else if (horizontalProximityFill) {                            /* Run doesn't cross vertical midline */
          c1.xPixel = Math.floor ((c1.x + c2.x) / 2.0);
          c2.xPixel = c1.xPixel + 1; }
        
        else {
          c1.xPixel = leftRun;
          c2.xPixel = rightRun; }
        
        lastX = Math.max (lastX, c2.x); }}
  }
  
  private void editWhiteSpace () {
    //TODO
  }
  
  private void returnBits (BitmapConsumer bitmapConsumer) {
    for (int y = firstScanline; y <= lastScanline; y++) {
      List/**/ crosses = getScanline (y);

      for (Iterator it = crosses.iterator(); it.hasNext (); ) {
        IntersectionCross c1 = (IntersectionCross) it.next ();
        if (!it.hasNext ()) {
          System.err.println ("unpaired cross at y=" + y); 
          continue; }
        IntersectionCross c2 = (IntersectionCross) it.next ();
        
        double left = c1.xPixel;
        double right = c2. xPixel;
        
        if (left < right) {
          bitmapConsumer.addRun (left, right, y); }}}
  }
  
  private void paintCrosses (boolean iCrossesOnly) {    
    for (Iterator it = contours.iterator(); it.hasNext (); ) {
      Contour contour = (Contour) it.next (); 
      for (Iterator it2 = contour.iterator(); it2.hasNext (); ) {
        Cross c = (Cross) it2.next ();
        if ((!iCrossesOnly) || (c instanceof IntersectionCross)) {
          outlineDebugger.cscanCross (c.x, c.y); }}}
  }

//  
//  private Color[] colors = {Color.RED, Color.GREEN};
//
//  public void paintEdges (Graphics2D g2) {
//    for (Iterator contoursIterator = contours.iterator (); contoursIterator.hasNext (); ) {
//      Contour contour = (Contour) contoursIterator.next ();
//      int c = 0;
//      for (Contour.EdgeIterator edgeIterator = contour.iterateEdges (); edgeIterator.hasNext (); ) {
//        edgeIterator.next ();
//        Cross cc1 = edgeIterator.c1 ();
//        Cross cc2 = edgeIterator.c2 ();
//        
//        g2.setColor (colors [c]);
//        c = (c + 1) % colors.length;
//        g2.draw (new Line2D.Double (cc1.x, cc1.y, cc2.x, cc2.y)); }}
//  }
//  
//  public void paintSnappedOutline (Graphics2D g2) {
//    final double width = 0.06;
//    final double offset = 0.03 + width / 2.0d ;
//    
//    g2.setColor (Color.RED);
//    g2.setStroke (new BasicStroke ((float) (width)));
//    
//    for (Iterator contoursIterator = contours.iterator (); contoursIterator.hasNext (); ) {
//      Contour contour = (Contour) contoursIterator.next ();
//
//      for (Contour.IntersectionEdgeIterator edgeIterator = contour.iterateIntersectionEdges (); edgeIterator.hasNext (); ) {
//        edgeIterator.next ();
//        IntersectionCross c1 = edgeIterator.c1 ();
//        IntersectionCross c2 = edgeIterator.c2 ();
//        
//        double x1, y1, ymid, x2, y2;
//        
//        x1 = c1.xPixel; 
//        y1 = c1.y;
//        x2 = c2.xPixel;
//        y2 = c2.y;
//                
//        Cross c3 = c1.contour.adjacentCross(c1, Contour.FORWARD);
//        if (c3.y < c1.y) {
//          ymid = Math.floor (c1.y);
//          ymid += ((x2 > x1) ? -offset : +offset); }
//        else {
//          ymid = Math.ceil (c1.y);
//          ymid += ((x2 < x1) ? +offset : -offset); }
//
//        x1 += (c1.isLeftInRun() ? -offset : +offset);
//        x2 += (c2.isLeftInRun() ? -offset : +offset);
//        
//        g2.draw (new Line2D.Double (x1, y1, x1, ymid));
//        g2.draw (new Line2D.Double (x1, ymid, x2, ymid));
//        g2.draw (new Line2D.Double (x2, ymid, x2, y2)); }}
//  }
//  
//  public void paintDropouts (Graphics2D g2) {
//    if (configuration.drawHDropouts)  {
//      for (int y = firstScanline; y <= lastScanline; y++) {
//        SortedSet/**/ crosses = getScanline (y);
//        for (Iterator it = crosses.iterator(); it.hasNext (); ) {
//          IntersectionCross c1 = (IntersectionCross) it.next ();
//          IntersectionCross c2 = (IntersectionCross) it.next ();
//          if (c1.xPixel == c2.xPixel) {
//            drawDropout (g2, c1.xPixel, c1.y, true); }}}}
//    
//    if (configuration.drawVDropouts) {
//      for (Iterator contoursIterator = contours.iterator (); contoursIterator.hasNext (); ) {
//        Contour contour = (Contour) contoursIterator.next ();
//        
//        for (Contour.IntersectionEdgeIterator it = contour.iterateIntersectionEdges(); it.hasNext(); ) {
//          it.next();
//          IntersectionCross c1 = it.c1();
//          IntersectionCross c2 = it.c2();
//          
//          double ymid;
//          { Cross c3 = c1.contour.adjacentCross(c1, Contour.FORWARD);
//          if (c3.y < c1.y) {
//            ymid = Math.floor (c1.y); }
//          else {
//            ymid = Math.ceil (c1.y); }}
//          
//          if (c1.x > c2.x) {
//            IntersectionCross tmp = c1; c1 = c2; c2 = tmp; }
//          
//          if (c1.isLeftInRun ()) {
//            IntersectionCross c = c1;
//            while (c != null && c.xPixel < c2.xPixel) {
//              IntersectionCross cr = c.rightInRun ();
//              if (! c.isLeftInRun ()) {
//                dropouts (g2,
//                    c.xPixel,
//                    (cr != null) ? Math.min (c2.xPixel, cr.xPixel) : c2.xPixel,
//                        ymid); }
//              c = cr; }}
//          
//          else if (c2.y != c1.y) {
//            IntersectionCross c = c2;
//            while (c != null && c1.xPixel < c.xPixel) {
//              IntersectionCross cl = c.leftInRun ();
//              if (c.isLeftInRun ()) {
//                dropouts (g2,
//                    (cl != null) ? Math.max (c1.xPixel, cl.xPixel) : c1.xPixel,
//                        c.xPixel,
//                        ymid); }
//              c = cl; }}
//          
//          else if (ymid > c1.y) { // goes up and right and down on the same line, ink on the outside and above
//            IntersectionCross c = leftMostAbove (c1);
//            
//            if (c == null) {
//              dropouts (g2, c1.xPixel, c2.xPixel, ymid); }
//            
//            else {
//              if (c1.xPixel < c.xPixel && c.isLeftInRun ())  {
//                dropouts (g2, c1.xPixel, Math.min (c2.xPixel, c.xPixel), ymid); }
//              
//              while (c != null && c.xPixel < c2.xPixel) {
//                IntersectionCross cr = c.rightInRun ();
//                if (! c.isLeftInRun ()) {
//                  dropouts (g2, 
//                      c.xPixel,
//                      (cr != null) ? Math.min (c2.xPixel, cr.xPixel) : c2.xPixel,
//                          ymid); }
//                c = cr; }}}}}}
//    
//    if (configuration.drawEDropouts) {
//      for (Iterator/**/ it = crossesAtXMinima.iterator (); it.hasNext (); )  {
//        Cross c = (Cross) it.next (); 
//        
//        IntersectionCross c1 = c.contour.adjacentIntersectionCross (c, Contour.FORWARD);
//        if (! c1.isLeftInRun ()) {
//          c1 = c1.leftInRun (); }
//        IntersectionCross c2 = c.contour.adjacentIntersectionCross (c, Contour.BACKWARD);
//        if (! c2.isLeftInRun ()) {
//          c2 = c2.leftInRun (); }        
//        if (c2.xPixel < c1.xPixel) {
//          c1 = c2; }         
//        dropouts (g2, Math.round (c.x), c1.xPixel, Math.round (c.y)); }
//      
//      
//      for (Iterator/**/ it = crossesAtXMaxima.iterator (); it.hasNext (); )  {
//        Cross c = (Cross) it.next (); 
//        
//        IntersectionCross c1 = c.contour.adjacentIntersectionCross (c, Contour.FORWARD);
//        if (! c1.isLeftInRun ()) {
//          c1 = c1.leftInRun (); }
//        IntersectionCross c2 = c.contour.adjacentIntersectionCross (c, Contour.BACKWARD);
//        if (! c2.isLeftInRun ()) {
//          c2 = c2.leftInRun (); }
//        if (c1.rightInRun().xPixel < c2.rightInRun().xPixel) {
//          c1 = c2; }
//        dropouts (g2, c1.rightInRun().xPixel, Math.round (c.x), Math.round (c.y)); }}
//  }
  
//  private IntersectionCross leftMostAbove (IntersectionCross c) {
//    SortedSet/**/ scanline = getScanline ((int) (c.y + 1));
//    
//    for (Iterator it = scanline.iterator (); it.hasNext (); ) {
//      IntersectionCross cAbove = (IntersectionCross) it.next ();
//      if (c.xPixel <= cAbove.xPixel) {
//        return cAbove; }}
//    
//    return null; 
//  }

  
//  private void dropouts (Graphics2D g2, double xleft, double xright, double y) {
//    for (double x = xleft + 0.5; x < xright; x++) {
//      drawDropout (g2, x, y, false); }
//  }
//  
//  private void drawDropout (Graphics2D g2, double x, double y, boolean horizontal) {
//    g2.setColor (Color.GREEN);
//    final double w = 0.25;
//    if (horizontal) {
//      g2.fill (new Rectangle2D.Double (x-w, y-w/2.0d, 2*w, w)); }
//    else {
//      g2.fill (new Rectangle2D.Double (x-w/2.0d, y-w, w, 2*w)); }
//  }
  
  private final static List/**/ emptyScanline = new LinkedList ();
  
  private List/**/ getScanline (int y) {
    List/**/ scanline = (LinkedList/**/) scanLines.get (new Integer (y));
    if (scanline == null) {
      scanline = emptyScanline; }
    return scanline;
  }
  
  
  //----------------------------------------------------------------------------
  private ScalerDebugger outlineDebugger;
  public void setDebugger (ScalerDebugger outlineDebugger) {
    this.outlineDebugger = outlineDebugger;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy