Aus Spass: per IL eine Linie zeichnen, mit Antialiasing

Kleine Tipps & Tricks für die tägliche Arbeit mit Director.

Moderatoren: Bär, Admin

Antworten
Benutzeravatar
mc_hammer
Specialist
Beiträge: 125
Registriert: 15.02.2006, 2006 11:04
Wohnort: CH - Lenzburg
Kontaktdaten:

Aus Spass: per IL eine Linie zeichnen, mit Antialiasing

Beitrag von mc_hammer » 18.07.2007, 2007 13:51

Hi there!

Wenn mal Antialiasing erwünscht ist, dann gibt die draw() - Funktion leider ned viel her. Also hab ich mich aus Spass an der Sache mich mal hingesetzt und eine eigene Linienfunktion geschrieben, welche eine Linie in ein Image-Objekt zeichnet. Wahlweise eben mit oder ohne Antialiasing :-)

Gar nicht so einfach, wenn man von Algorithmen bzgl. grafischer Verarbeitung keine grosse Ahnung hat. Das Problem ist grundlegend: wie wird eine Linie gerastert? Diesbezüglich habe ich mich am Bresenham-Algorithmus orientiert:
http://de.wikipedia.org/wiki/Rastern_von_Linien

Das Antialiasing habe ich letztendlich ein bisschen nach Try- und Errorverfahren hingeknurzt, bis es endlich schön aussah. Es wird auf das übergebene Image-Objekt darübergerechnet, schon fast Photoshop-Qualitäten ;-)

Hier Die Klasse (Parent-Script):

Code: Alles auswählen

--************************************************************************
-- Autor:   Oliver Mischa Voegeli
-- Version: 1.0
-- Datum:   17.07.2007
-- Klasse zeichnet eine Linie nach dem Bresenham-Verfahren, mit Anti-
-- Aliasing falls erwünscht
--************************************************************************



on drawLine (me, pointFrom, pointTo, destImg, theLineSize, theColor, antialiased)
  start = the milliseconds
  if (theColor = void OR ilk(theColor) <> #color) then theColor = rgb(0,0,0) --schwarz als default
  if (ilk(pointFrom) <> #point or ilk(pointTo) <> #point) then 
    alert("Fehlerhafe Parameterübergabe in drawLine(); points erwartet")
    return
  end if
  if (ilk(destImg) <> #image) then 
    alert("Fehlerhafe Parameterübergabe in drawLine(); Image-Referenz erwartet")
    return
  end if
  
  if ilk(theLineSize) <integer> abs(y2-y1) then 
    
    -- Steigung < 1
    if x1 = x2 then return
    DeltaY_float = (y2-y1)/float(x2-x1)  -- entspricht der Steigung m
    Y_float = y1                         -- entspricht Achsenabschnitt q
    steps = abs(x2-x1)
    if x1 <x2> 1
    if y1 = y2 then return
    DeltaX_float = -(x2-x1)/float(y2-y1)  -- entspricht der Steigung m
    X_float = x1                          -- entspricht Achsenabschnitt q
    steps = abs(y2-y1)
    if y1 > y2 then
      
      repeat with i = 0 to steps  -- von links nach rechts
        me.paintPixelY(destImg, i, y1, X_float, antialiased, theColor, theLineSize)
        X_float = X_float + DeltaX_float     
      end repeat
      
    else  
      
      repeat with i = steps down to 0  -- von rechts nach links
        me.paintPixelY(destImg, i, y2, X_float, antialiased, theColor, theLineSize)
        X_float = X_float - DeltaX_float
      end repeat
      
    end if
    
  end if
  put "Dauer: " & the milliseconds - start
end


-- PRIVAT ***********************************************************************************************
-- Zeichnet Liniendicke in Y-Richtung (Steigung <1> 1)
on paintLineSizeX (me, destImg, x, y, theLineSize, theColor)
  repeat with lineSize = 1 to theLineSize - 1
    destImg.setPixel(x+lineSize, y, theColor)
  end repeat
end


-- Iterator in X-Richtung, zeichnet Linie Pixelweise
on paintPixelX (me, destImg, i, x1, Y_float, antialiased, theColor, theLineSize)
  destX = x1+i
  Y = me.getGanzzahl(Y_float)
  
  if antialiased then  -- mit antialiasing
    antiAliasingOffset = me.getFloor(Y_float)
    
    destColor = destImg.getPixel(destX, Y)
    antiAColor = me.calculateColorDiff(destColor, theColor, antiAliasingOffset)
    destImg.setPixel(destX, Y, antiAColor)
    
    me.paintLineSizeY(destImg, destX, Y, theLineSize, theColor)
    
    destColor = destImg.getPixel(destX, Y-theLineSize)
    diffColor = me.calculateColorDiff(destColor, theColor, 1 - antiAliasingOffset)
    destImg.setPixel(destX, Y-theLineSize, diffColor)
    
  else   -- ohne antialiasing
    
    me.paintLineSizeY(destImg, destX, Y, theLineSize+1, theColor)
    
  end if
  
end

-- Iterator in Y-Richtung, zeichnet Linie Pixelweise
on paintPixelY (me, destImg, i, y1, X_float, antialiased, theColor, theLineSize)
  destY = y1-i
  X = me.getGanzzahl(X_float)
  
  if antialiased then  -- mit antialiasing
    antiAliasingOffset = 1 - me.getFloor(X_float)
    
    destColor = destImg.getPixel(X, destY)
    antiAColor = me.calculateColorDiff(destColor, theColor, antiAliasingOffset)
    destImg.setPixel(X, destY, antiAColor)
    
    me.paintLineSizeX(destImg, X, destY, theLineSize, theColor)
    
    destColor = destImg.getPixel(X+theLineSize, destY)
    diffColor = me.calculateColorDiff(destColor, theColor, 1 - antiAliasingOffset)
    destImg.setPixel(X+theLineSize, destY, diffColor) 
    
  else   -- ohne antialiasing
    
    me.paintLineSizeX(destImg, X, destY, theLineSize+1, theColor)
    
  end if
  
end


-- Hilfsmethode berechnet für das antialiasing den Differenz-Colorwert, abhängig von 0<antiAliasingOffset<1> 0.67
on getFloor me, floatZahl
  floor = integer(floatZahl-0.5)
  return floatZahl - floor
end


on getGanzzahl (me, x)
  -- floor moves left on the number line (negative numbers are 
  -- 'floored' away from 0). 
  intX = bitOr( x, 0 )
  if( x = intX ) then return intX
  else if( x > 0 ) then return intX
  else return intX - 1
end
Die Methode drawLine nimmt folgende Parameter entgegen:
- Startpunkt: point()
- Endpunkt: point()
- Zielbitmap: #image
- Liniendicke: #integer
- Farbe: #color (rgb)
- Antialiasing (ein/aus): #bool

Nun braucht ihr daneben nur noch einen Bitmap-Darsteller und los geht's:

Code: Alles auswählen

script("DrawLineBresenham_class").new().drawLine(point(40,50),point(100,100),member("dein_bitmap").image, 2, rgb(0,0,255), true)
Mathematiker werden vermutlich die Nase rümpfen, ich bin mir sicher man könnte den Algorithmus noch optimieren. Aber für meine Zwecke tut's! 8)

Grüsse
Oliver

Edith: Bugs ausgemerzt

Antworten

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast