/* Numérise un coté de (X1,Y1) en (X2,Y2), ce qui n'inclut pas le point en (X2,Y2). Si SkipFirst == 1, le point en (X1,Y1) n'est pas affiché; si SkipFirst == 0, il l'est. Pour chaque ligne d'affichage, le pixel le plus proche du coté parcouru qui n'est pas à sa gauche est choisi. Utilise une approche "tout entier", pour la vitesse et la précision Lié avec L21-1.C, L21-3.C, et L22-1.C en modèle Compact. Testé avec Borland C++ 4.02 par Jim Mischel 12/16/94. */ #include #include "polygon.h" void ScanEdge(int X1, int Y1, int X2, int Y2, int SetXStart, int SkipFirst, struct HLine **EdgePointPtr) { int Y, DeltaX, Height, Width, AdvanceAmt, ErrorTerm, i; int ErrorTermAdvance, XMajorAdvanceAmt; struct HLine *WorkingEdgePointPtr; WorkingEdgePointPtr = *EdgePointPtr; /* évite une double déréférence */ AdvanceAmt = ((DeltaX = X2 - X1) > 0) ? 1 : -1; /* direction dans laquelle X se déplace (Y2 est toujours > Y1, aussi Y augmente toujours) */ if ((Height = Y2 - Y1) <= 0) /* longueur Y du coté */ return; /* évite les cotés de longueur 0 et horizontaux */ /* Détermine si le coté est vertical, diagonal, X principal (le plus horizontal), ou Y principal (le plus vertical) et traite selon */ if ((Width = abs(DeltaX)) == 0) { /* Le coté est vertical; cas particulier en stockant simplement la même coordonnée X pour chaque ligne d'affichage */ for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) { /* Stocke la coordonnée X dans la liste de coté appropriée */ if (SetXStart == 1) WorkingEdgePointPtr->XStart = X1; else WorkingEdgePointPtr->XEnd = X1; } } else if (Width == Height) { /* Le coté est diagonal; cas particulier en avançant la coordonnée X d'1 pixel pour chaque ligne d'affichage */ if (SkipFirst) /* saute le premier point si indiqué */ X1 += AdvanceAmt; /* déplace 1 pixel à gauche ou à droite */ /* Numérise le coté pour chaque ligne d'affichage */ for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) { /* Stocke la coordonnée X dans la liste de coté appropriée */ if (SetXStart == 1) WorkingEdgePointPtr->XStart = X1; else WorkingEdgePointPtr->XEnd = X1; X1 += AdvanceAmt; /* déplace 1 pixel à gauche ou à droite */ } } else if (Height > Width) { /* Le coté est plus proche de la verticale que de l'horizontale (Y principale ) */ if (DeltaX >= 0) ErrorTerm = 0; /* terme d'erreur initial allant gauche ->droite */ else ErrorTerm = -Height + 1; /* allant droite ->gauche */ if (SkipFirst) { /* saute le premier point si indiqué */ /* Détermine s'il est temps d'avancer la coordonnée X */ if ((ErrorTerm += Width) > 0) { X1 += AdvanceAmt; /* déplace 1 pixel à gauche ou à droite */ ErrorTerm -= Height; /* avance ErrorTerm au prochain point */ } } /* Parcourt le coté pour chaque ligne d'affichage l'une après l'autre */ for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) { /* Stocke la coordonnée X dans la liste de coté appropriée */ if (SetXStart == 1) WorkingEdgePointPtr->XStart = X1; else WorkingEdgePointPtr->XEnd = X1; /* Determine s'il est temps d'avancer la coordonnée X */ if ((ErrorTerm += Width) > 0) { X1 += AdvanceAmt; /* déplace 1 pixel à gauche ou à droite */ ErrorTerm -= Height; /* avance ErrorTerm pour correspondre */ } } } else { /* Le coté est plus proche de l'horizontale que de la verticale (X principale) */ /* Distance minimale pour avancer X chaque fois */ XMajorAdvanceAmt = (Width / Height) * AdvanceAmt; /* Le terme d'erreur avance pour décider quand il faut avancer X de plus 1 */ ErrorTermAdvance = Width % Height; if (DeltaX >= 0) ErrorTerm = 0; /* terme d'erreur gauche->droite */ else ErrorTerm = -Height + 1; /* droite ->gauche */ if (SkipFirst) { /* saute le premier point si indiqué */ X1 += XMajorAdvanceAmt; /* déplace X de la distance minimale */ /* Détermine s'il est temps d'avancer de 1 la coordonnée X */ if ((ErrorTerm += ErrorTermAdvance) > 0) { X1 += AdvanceAmt; /* déplace X encore une fois */ ErrorTerm -= Height; /* avance ErrorTerm pour correspondre */ } } /* Parcourt le coté pour chaque ligne d'affichage l'une après l'autre */ for (i = Height - SkipFirst; i-- > 0; WorkingEdgePointPtr++) { /* Stocke la coordonnée X dans la liste de coté appropriée */ if (SetXStart == 1) WorkingEdgePointPtr->XStart = X1; else WorkingEdgePointPtr->XEnd = X1; X1 += XMajorAdvanceAmt; /* déplace X de la distance minimale */ /* Détermine s'il est temps d'avancer la coordonnée X de 1 */ if ((ErrorTerm += ErrorTermAdvance) > 0) { X1 += AdvanceAmt; /* déplace X encore une fois */ ErrorTerm -= Height; /* avance ErrorTerm pour correspondre */ } } } *EdgePointPtr = WorkingEdgePointPtr; /* avance ptr de l'appelant */ }