/*******************************/ /**** Routine de trace HPGL ****/ /*******************************/ #include "fctsys.h" #include "common.h" #include "plot_common.h" #include "pcbnew.h" #include "pcbplot.h" #include "trigo.h" #include "protos.h" /* Variables locales : */ static int pen_rayon; /* Rayon de la plume en unites pcb */ static int pen_diam; /* Diametre de la plume en unites pcb */ static int pen_recouvrement; /* recouvrement en remplissage en unites pcb */ /* Routines Locales */ /*****************************************************************************/ void WinEDA_BasePcbFrame::Genere_HPGL( const wxString& FullFileName, int Layer ) /*****************************************************************************/ { int modetrace; wxSize SheetSize; wxSize BoardSize; wxPoint BoardCenter; double scale_x, scale_y; int marge = 0 * U_PCB; // Extra margin (set to 0) bool Center = FALSE; modetrace = Plot_Mode; /* Calcul des echelles de conversion */ scale_x = Scale_X * SCALE_HPGL; scale_y = Scale_Y * SCALE_HPGL; // calcul en unites internes des dimensions de la feuille ( connues en 1/1000 pouce ) SheetSize.x = GetScreen()->m_CurrentSheetDesc->m_Size.x * U_PCB; SheetSize.y = GetScreen()->m_CurrentSheetDesc->m_Size.y * U_PCB; g_PlotOffset.x = 0; g_PlotOffset.y = (int) (SheetSize.y * scale_y); // Compute pen_dim (from g_HPGL_Pen_Diam in mils) in pcb units, // with plot scale (if Scale is 2, pen diametre is always g_HPGL_Pen_Diam // so apparent pen diam is real pen diam / Scale pen_diam = (int) round( (g_HPGL_Pen_Diam * U_PCB) / Scale_X ); // Assume Scale_X # Scale_Y pen_rayon = pen_diam / 2; nb_plot_erreur = 0; // compute pen_recouvrement (from g_HPGL_Pen_Recouvrement in mils) // with plot scale if( g_HPGL_Pen_Recouvrement < 0 ) g_HPGL_Pen_Recouvrement = 0; if( g_HPGL_Pen_Recouvrement >= g_HPGL_Pen_Diam ) g_HPGL_Pen_Recouvrement = g_HPGL_Pen_Diam - 1; pen_recouvrement = (int) round( g_HPGL_Pen_Recouvrement * 10.0 / Scale_X ); dest = wxFopen( FullFileName, wxT( "wt" ) ); if( dest == NULL ) { wxString msg = _( "Unable to create " ) + FullFileName; DisplayError( this, msg ); return; } SetLocaleTo_C_standard( ); Affiche_1_Parametre( this, 0, _( "File" ), FullFileName, CYAN ); PrintHeaderHPGL( dest, g_HPGL_Pen_Speed, g_HPGL_Pen_Num ); if( Plot_Sheet_Ref && (g_PlotScaleOpt == 1) ) { int tmp = g_PlotOrient; g_PlotOrient = 0; InitPlotParametresHPGL( g_PlotOffset, scale_x, scale_y, g_PlotOrient ); PlotWorkSheet( PLOT_FORMAT_HPGL, GetScreen() ); g_PlotOrient = tmp; } /* calcul des dimensions et centre du PCB */ m_Pcb->ComputeBoundaryBox(); BoardSize = m_Pcb->m_BoundaryBox.GetSize(); BoardCenter = m_Pcb->m_BoundaryBox.Centre(); if( g_PlotScaleOpt == 0 ) // Optimum scale { float Xscale, Yscale; Xscale = (float) ( SheetSize.x - ( 2 * marge) ) / BoardSize.x; Yscale = (float) ( SheetSize.y - ( 2 * marge) ) / BoardSize.y; scale_x = scale_y = MIN( Xscale, Yscale ) * SCALE_HPGL; } BoardCenter.x = (int) (BoardCenter.x * scale_x); BoardCenter.y = (int) (BoardCenter.y * scale_y); if( g_PlotScaleOpt != 1 ) Center = TRUE; // Echelle != 1 /* Calcul du cadrage */ marge = (int) (marge * SCALE_HPGL); if( Center ) g_PlotOffset.x = (int) (-SheetSize.x / 2 * SCALE_HPGL) + BoardCenter.x + marge; switch( g_PlotOrient ) { default: if( Center ) { g_PlotOffset.y = (int) (SheetSize.y / 2 * SCALE_HPGL) + BoardCenter.y + marge; } break; case PLOT_MIROIR: if( Center ) g_PlotOffset.y = (int) (-SheetSize.y / 2 * SCALE_HPGL) + BoardCenter.y; else g_PlotOffset.y = (int) ( ( -SheetSize.y + m_Pcb->m_BoundaryBox.GetBottom() + m_Pcb->m_BoundaryBox.GetY() ) * SCALE_HPGL ); break; } InitPlotParametresHPGL( g_PlotOffset, scale_x, scale_y, g_PlotOrient ); // Specify that the contents of the "Edges Pcb" layer are to be plotted // in addition to the contents of the currently specified layer. int layer_mask = g_TabOneLayerMask[Layer] | EDGE_LAYER; switch( Layer ) { case FIRST_COPPER_LAYER: case LAYER_N_2: case LAYER_N_3: case LAYER_N_4: case LAYER_N_5: case LAYER_N_6: case LAYER_N_7: case LAYER_N_8: case LAYER_N_9: case LAYER_N_10: case LAYER_N_11: case LAYER_N_12: case LAYER_N_13: case LAYER_N_14: case LAYER_N_15: case LAST_COPPER_LAYER: Plot_Layer_HPGL( dest, layer_mask, 0, 1, modetrace ); break; case SILKSCREEN_N_CU: case SILKSCREEN_N_CMP: Plot_Serigraphie( PLOT_FORMAT_HPGL, dest, layer_mask ); break; case SOLDERMASK_N_CU: case SOLDERMASK_N_CMP: /* Trace du vernis epargne */ { int tracevia; if( g_DrawViaOnMaskLayer ) tracevia = 1; else tracevia = 0; Plot_Layer_HPGL( dest, layer_mask, g_DesignSettings.m_MaskMargin, tracevia, modetrace ); } break; case SOLDERPASTE_N_CU: case SOLDERPASTE_N_CMP: /* Trace du masque de pate de soudure */ Plot_Layer_HPGL( dest, layer_mask, 0, 0, modetrace ); break; default: /* Trace des autres couches (dessin, adhesives,eco,comment) */ Plot_Serigraphie( PLOT_FORMAT_HPGL, dest, layer_mask ); break; } /* fin */ CloseFileHPGL( dest ); SetLocaleTo_Default( ); } /*********************************************************************/ void WinEDA_BasePcbFrame::Plot_Layer_HPGL( FILE* File, int masque_layer, int garde, int tracevia, int modetrace ) /*********************************************************************/ /* Trace en format HPGL. d'une couche cuivre ou masque * 1 unite HPGL = 0.98 mils ( 1 mil = 1.02041 unite HPGL ) . */ { wxSize size; wxPoint start, end; MODULE* Module; D_PAD* PtPad; TRACK* pts; BOARD_ITEM* PtStruct; wxString msg; // (Following command has been superceded by new command on line 135.) // masque_layer |= EDGE_LAYER; /* Les elements de la couche EDGE sont tj traces */ /* trace des elements type Drawings Pcb : */ PtStruct = m_Pcb->m_Drawings; for( ; PtStruct != NULL; PtStruct = PtStruct->Next() ) { switch( PtStruct->Type() ) { case TYPEDRAWSEGMENT: PlotDrawSegment( (DRAWSEGMENT*) PtStruct, PLOT_FORMAT_HPGL, masque_layer ); break; case TYPETEXTE: PlotTextePcb( (TEXTE_PCB*) PtStruct, PLOT_FORMAT_HPGL, masque_layer ); break; case TYPECOTATION: PlotCotation( (COTATION*) PtStruct, PLOT_FORMAT_HPGL, masque_layer ); break; case TYPEMIRE: PlotMirePcb( (MIREPCB*) PtStruct, PLOT_FORMAT_HPGL, masque_layer ); break; case TYPEMARKER: break; default: DisplayError( this, wxT( "Type Draw non gere" ) ); break; } } /* Trace des Elements des modules autres que pads */ nb_items = 0; Affiche_1_Parametre( this, 48, wxT( "DrawMod" ), wxEmptyString, GREEN ); Module = m_Pcb->m_Modules; for( ; Module != NULL; Module = (MODULE*) Module->Pnext ) { PtStruct = Module->m_Drawings; for( ; PtStruct != NULL; PtStruct = PtStruct->Next() ) { switch( PtStruct->Type() ) { case TYPEEDGEMODULE: if( masque_layer & g_TabOneLayerMask[ PtStruct->GetLayer() ] ) Plot_1_EdgeModule( PLOT_FORMAT_HPGL, (EDGE_MODULE*) PtStruct ); break; default: break; } } } /* Trace des Elements des modules : Pastilles */ nb_items = 0; Affiche_1_Parametre( this, 48, wxT( "Pads " ), wxEmptyString, GREEN ); Module = m_Pcb->m_Modules; for( ; Module != NULL; Module = (MODULE*) Module->Pnext ) { PtPad = (D_PAD*) Module->m_Pads; for( ; PtPad != NULL; PtPad = (D_PAD*) PtPad->Pnext ) { wxPoint shape_pos; if( (PtPad->m_Masque_Layer & masque_layer) == 0 ) continue; shape_pos = PtPad->ReturnShapePos(); start = shape_pos; size = PtPad->m_Size; size.x += garde * 2; size.y += garde * 2; nb_items++; switch( PtPad->m_PadShape & 0x7F ) { case PAD_CIRCLE: trace_1_pastille_RONDE_HPGL( start, size.x, modetrace ); break; case PAD_OVAL: { trace_1_pastille_OVALE_HPGL( start, size, PtPad->m_Orient, modetrace ); break; } case PAD_TRAPEZOID: { wxSize delta; delta = PtPad->m_DeltaSize; trace_1_pad_TRAPEZE_HPGL( start, size, delta, PtPad->m_Orient, modetrace ); break; } case PAD_RECT: default: PlotRectangularPad_HPGL( start, size, PtPad->m_Orient, modetrace ); break; } msg.Printf( wxT( "%d" ), nb_items ); Affiche_1_Parametre( this, 48, wxT( "Pads" ), msg, GREEN ); } } /* trace des VIAS : */ if( tracevia ) { TRACK* pts; nb_items = 0; Affiche_1_Parametre( this, 56, wxT( "Vias" ), wxEmptyString, RED ); for( pts = m_Pcb->m_Track; pts != NULL; pts = (TRACK*) pts->Pnext ) { if( pts->Type() != TYPEVIA ) continue; SEGVIA* Via = (SEGVIA*) pts; /* vias not plotted if not on selected layer, but if layer * == SOLDERMASK_LAYER_CU or SOLDERMASK_LAYER_CMP, vias are drawn , * if they are on a external copper layer */ int via_mask_layer = Via->ReturnMaskLayer(); if( (via_mask_layer & CUIVRE_LAYER ) ) via_mask_layer |= SOLDERMASK_LAYER_CU; if( (via_mask_layer & CMP_LAYER ) ) via_mask_layer |= SOLDERMASK_LAYER_CMP; if( (via_mask_layer & masque_layer) == 0 ) continue; start = Via->m_Start; size.x = Via->m_Width + (garde * 2); trace_1_pastille_RONDE_HPGL( start, size.x, modetrace ); nb_items++; msg.Printf( wxT( "%d" ), nb_items ); Affiche_1_Parametre( this, 56, wxT( "Vias" ), msg, RED ); } fputs( "PU;\n", dest ); } /* trace des segments pistes */ nb_items = 0; Affiche_1_Parametre( this, 64, wxT( "Tracks " ), wxEmptyString, YELLOW ); for( pts = m_Pcb->m_Track; pts != NULL; pts = (TRACK*) pts->Pnext ) { if( pts->Type() == TYPEVIA ) continue; if( (g_TabOneLayerMask[pts->GetLayer()] & masque_layer) == 0 ) continue; size.x = size.y = pts->m_Width; start = pts->m_Start; end = pts->m_End; if( size.x > pen_diam ) /* c.a.d si largeur piste > diam plume */ trace_1_pastille_RONDE_HPGL( start, size.x, modetrace ); /* Trace d'un segment de piste */ trace_1_segment_HPGL( start.x, start.y, end.x, end.y, size.x ); /* Complement de Trace en mode Remplissage */ if( (Plot_Mode == FILLED) && (pen_diam <= size.x ) ) { while( ( size.x -= (int) ( (pen_rayon - pen_recouvrement) * 2 ) ) > 0 ) { trace_1_segment_HPGL( start.x, start.y, end.x, end.y, MAX( size.x, pen_diam ) ); } } if( size.x > pen_diam ) trace_1_pastille_RONDE_HPGL( end, size.x, modetrace ); nb_items++; msg.Printf( wxT( "%d" ), nb_items ); Affiche_1_Parametre( this, 64, wxEmptyString, msg, YELLOW ); } /* trace des segments pistes et zones */ nb_items = 0; Affiche_1_Parametre( this, 64, wxT( "Zones " ), wxEmptyString, YELLOW ); for( pts = m_Pcb->m_Zone; pts != NULL; pts = (TRACK*) pts->Pnext ) { if( g_TabOneLayerMask[pts->GetLayer()] & masque_layer ) { size.x = size.y = pts->m_Width; start = pts->m_Start; end = pts->m_End; if( size.x > pen_diam ) /* c.a.d si largeur piste > diam plume */ trace_1_pastille_RONDE_HPGL( start, size.x, modetrace ); /* Trace d'un segment de piste */ trace_1_segment_HPGL( start.x, start.y, end.x, end.y, size.x ); /* Complement de Trace en mode Remplissage */ if( (Plot_Mode == FILLED) && (pen_diam <= size.x ) ) { while( ( size.x -= (int) ( (pen_rayon - pen_recouvrement) * 2 ) ) > 0 ) { trace_1_segment_HPGL( start.x, start.y, end.x, end.y, MAX( size.x, pen_diam ) ); } } if( size.x > pen_diam ) trace_1_pastille_RONDE_HPGL( end, size.x, modetrace ); nb_items++; msg.Printf( wxT( "%d" ), nb_items ); Affiche_1_Parametre( this, 64, wxEmptyString, msg, YELLOW ); } } } /************************************************************************************/ void trace_1_pastille_OVALE_HPGL( wxPoint pos, wxSize size, int orient, int modetrace ) /************************************************************************************/ /* Trace 1 pastille PAD_OVAL en position pos_X,Y , de dim size.x, size.y */ { int rayon, deltaxy, cx, cy; int trace_orient = orient; /* la pastille est ramenee a une pastille ovale avec size.y > size.x * ( ovale vertical en orientation 0 ) */ if( size.x > size.y ) { EXCHG( size.x, size.y ); trace_orient += 900; if( orient >= 3600 ) trace_orient -= 3600; } deltaxy = size.y - size.x; /* = distance entre centres de l'ovale */ rayon = size.x / 2; if( modetrace == FILLED ) { PlotRectangularPad_HPGL( pos, wxSize( size.x, deltaxy ), orient, modetrace ); cx = 0; cy = deltaxy / 2; RotatePoint( &cx, &cy, trace_orient ); trace_1_pastille_RONDE_HPGL( wxPoint( cx + pos.x, cy + pos.y ), size.x, modetrace ); Plume_HPGL( 'U' ); cx = 0; cy = -deltaxy / 2; RotatePoint( &cx, &cy, trace_orient ); trace_1_pastille_RONDE_HPGL( wxPoint( cx + pos.x, cy + pos.y ), size.x, modetrace ); } else /* Trace en mode FILAIRE */ { cx = -rayon; cy = -deltaxy / 2; RotatePoint( &cx, &cy, trace_orient ); Move_Plume_HPGL( wxPoint( cx + pos.x, cy + pos.y ), 'U' ); cx = -rayon; cy = deltaxy / 2; RotatePoint( &cx, &cy, trace_orient ); Move_Plume_HPGL( wxPoint( cx + pos.x, cy + pos.y ), 'D' ); cx = rayon; cy = -deltaxy / 2; RotatePoint( &cx, &cy, trace_orient ); Move_Plume_HPGL( wxPoint( cx + pos.x, cy + pos.y ), 'U' ); cx = rayon; cy = deltaxy / 2; RotatePoint( &cx, &cy, trace_orient ); Move_Plume_HPGL( wxPoint( cx + pos.x, cy + pos.y ), 'D' ); Plume_HPGL( 'U' ); cx = 0; cy = -deltaxy / 2; RotatePoint( &cx, &cy, trace_orient ); PlotArc( PLOT_FORMAT_HPGL, wxPoint( cx + pos.x, cy + pos.y ), trace_orient, trace_orient + 1800, size.x / 2, pen_diam ); cx = 0; cy = deltaxy / 2; RotatePoint( &cx, &cy, trace_orient ); PlotArc( PLOT_FORMAT_HPGL, wxPoint( cx + pos.x, cy + pos.y ), trace_orient + 1800, trace_orient, size.x / 2, pen_diam ); } Plume_HPGL( 'U' ); } /**************************************************************************/ void trace_1_pastille_RONDE_HPGL( wxPoint pos, int diametre, int modetrace ) /**************************************************************************/ /* Trace 1 pastille RONDE (via,pad rond) en position pos */ { char cbuf[1024]; int rayon, delta; UserToDeviceCoordinate( pos ); delta = pen_diam - pen_recouvrement; rayon = diametre / 2; if( modetrace != FILAIRE ) { rayon = (diametre - pen_diam ) / 2; } if( rayon < 0 ) { rayon = 0; nb_plot_erreur++; Affiche_erreur( nb_plot_erreur ); } wxSize rsize( rayon, rayon ); UserToDeviceSize( rsize ); Plume_HPGL( 'U' ); sprintf( cbuf, "PA %d,%d;CI %d;\n", pos.x, pos.y, rsize.x ); fputs( cbuf, dest ); if( modetrace == FILLED ) /* Trace en mode Remplissage */ { if( delta > 0 ) { while( (rayon -= delta ) >= 0 ) { rsize.x = rsize.y = rayon; UserToDeviceSize( rsize ); sprintf( cbuf, "PA %d,%d; CI %d;\n", pos.x, pos.y, rsize.x ); fputs( cbuf, dest ); } } } Plume_HPGL( 'U' ); return; } /***************************************************************/ void PlotRectangularPad_HPGL( wxPoint padpos, wxSize padsize, int orient, int modetrace ) /****************************************************************/ /* * Trace 1 pad rectangulaire vertical ou horizontal ( Pad rectangulaire ) * donne par son centre et ses dimensions X et Y * Units are user units */ { wxSize size; int delta; int ox, oy, fx, fy; size.x = padsize.x / 2; size.y = padsize.y / 2; if( modetrace != FILAIRE ) { size.x = (padsize.x - (int) pen_diam) / 2; size.y = (padsize.y - (int) pen_diam) / 2; } if( (size.x < 0 ) || (size.y < 0) ) { nb_plot_erreur++; Affiche_erreur( nb_plot_erreur ); } if( size.x < 0 ) size.x = 0;if( size.y < 0 ) size.y = 0; /* Si une des dimensions est nulle, le trace se reduit a 1 trait */ if( size.x == 0 ) { ox = padpos.x; oy = padpos.y - size.y; RotatePoint( &ox, &oy, padpos.x, padpos.y, orient ); fx = padpos.x; fy = padpos.y + size.y; RotatePoint( &fx, &fy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( ox, oy ), 'U' ); Move_Plume_HPGL( wxPoint( fx, fy ), 'D' ); Plume_HPGL( 'U' ); return; } if( size.y == 0 ) { ox = padpos.x - size.x; oy = padpos.y; RotatePoint( &ox, &oy, padpos.x, padpos.y, orient ); fx = padpos.x + size.x; fy = padpos.y; RotatePoint( &fx, &fy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( ox, oy ), 'U' ); Move_Plume_HPGL( wxPoint( fx, fy ), 'D' ); Plume_HPGL( 'U' ); return; } ox = padpos.x - size.x; oy = padpos.y - size.y; RotatePoint( &ox, &oy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( ox, oy ), 'U' ); fx = padpos.x - size.x; fy = padpos.y + size.y; RotatePoint( &fx, &fy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( fx, fy ), 'D' ); fx = padpos.x + size.x; fy = padpos.y + size.y; RotatePoint( &fx, &fy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( fx, fy ), 'D' ); fx = padpos.x + size.x; fy = padpos.y - size.y; RotatePoint( &fx, &fy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( fx, fy ), 'D' ); Move_Plume_HPGL( wxPoint( ox, oy ), 'D' ); if( modetrace != FILLED ) { Plume_HPGL( 'U' ); return; } /* Trace en mode Remplissage */ delta = (int) (pen_diam - pen_recouvrement); if( delta > 0 ) while( (size.x > 0) && (size.y > 0) ) { size.x -= delta; size.y -= delta; if( size.x < 0 ) size.x = 0;if( size.y < 0 ) size.y = 0; ox = padpos.x - size.x; oy = padpos.y - size.y; RotatePoint( &ox, &oy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( ox, oy ), 'D' ); fx = padpos.x - size.x; fy = padpos.y + size.y; RotatePoint( &fx, &fy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( fx, fy ), 'D' ); fx = padpos.x + size.x; fy = padpos.y + size.y; RotatePoint( &fx, &fy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( fx, fy ), 'D' ); fx = padpos.x + size.x; fy = padpos.y - size.y; RotatePoint( &fx, &fy, padpos.x, padpos.y, orient ); Move_Plume_HPGL( wxPoint( fx, fy ), 'D' ); Move_Plume_HPGL( wxPoint( ox, oy ), 'D' ); } Plume_HPGL( 'U' ); } /********************************************************************/ void trace_1_pad_TRAPEZE_HPGL( wxPoint padpos, wxSize size, wxSize delta, int orient, int modetrace ) /********************************************************************/ /* * Trace 1 pad trapezoidal donne par : * son centre padpos.x,padpos.y * ses dimensions dimX et dimY * les variations deltaX et deltaY * son orientation orient et 0.1 degres * le mode de trace (FILLED, SKETCH, FILAIRE) * Le trace n'est fait que pour un trapeze, c.a.d que deltaX ou deltaY * = 0. * * les notation des sommets sont ( vis a vis de la table tracante ) * 0 ------------- 3 * . . * . . * . . * 1 --- 2 */ { int ii, jj; wxPoint polygone[4]; /* coord des sommets / centre du pad */ wxPoint coord[4]; /* coord reelles des sommets du trapeze a tracer */ float fangle; /* angle d'inclinaison des cotes du trapeze */ int rayon; /* rayon de la plume */ int moveX, moveY;/* variation de position plume selon axe X et Y , lors * du remplissage du trapeze */ rayon = (int) pen_rayon; if( modetrace == FILAIRE ) rayon = 0; moveX = moveY = rayon; size.x /= 2; size.y /= 2; delta.x /= 2; delta.y /= 2; polygone[0].x = -size.x - delta.y; polygone[0].y = +size.y + delta.x; polygone[1].x = -size.x + delta.y; polygone[1].y = -size.y - delta.x; polygone[2].x = +size.x - delta.y; polygone[2].y = -size.y + delta.x; polygone[3].x = +size.x + delta.y; polygone[3].y = +size.y - delta.x; /* Calcul du demi angle d'inclinaison des cotes du trapeze */ if( delta.y ) /* Trapeze horizontal */ { fangle = atan2( (double) (polygone[1].y - polygone[0].y), (double) (polygone[1].x - polygone[0].x) ) / 2; } else { fangle = atan2( (double) (polygone[3].y - polygone[0].y), (double) (polygone[3].x - polygone[0].x) ) / 2; } /* Trace du contour */ polygone[0].x += moveX; polygone[0].y -= moveY; polygone[1].x += moveX; polygone[1].y += moveY; polygone[2].x -= moveX; polygone[2].y += moveY; polygone[3].x -= moveX; polygone[3].y -= moveY; for( ii = 0; ii < 4; ii++ ) { coord[ii].x = polygone[ii].x + padpos.x; coord[ii].y = polygone[ii].y + padpos.y; RotatePoint( &coord[ii], padpos, orient ); } // Plot edge: Move_Plume_HPGL( coord[0], 'U' ); Move_Plume_HPGL( coord[1], 'D' ); Move_Plume_HPGL( coord[2], 'D' ); Move_Plume_HPGL( coord[3], 'D' ); Move_Plume_HPGL( coord[0], 'D' ); if( modetrace != FILLED ) { Plume_HPGL( 'U' ); return; } /* Fill the shape */ moveX = moveY = pen_diam - pen_recouvrement; /* calcul de jj = hauteur du remplissage */ if( delta.y ) /* Trapeze horizontal */ { jj = size.y - (int) ( pen_diam + (2 * pen_recouvrement) ); } else { jj = size.x - (int) ( pen_diam + (2 * pen_recouvrement) ); } /* Calcul de jj = nombre de segments a tracer pour le remplissage */ jj = jj / (int) (pen_diam - pen_recouvrement); /* Trace du contour */ for( ; jj > 0; jj-- ) { polygone[0].x += moveX; polygone[0].y -= moveY; polygone[1].x += moveX; polygone[1].y += moveY; polygone[2].x -= moveX; polygone[2].y += moveY; polygone[3].x -= moveX; polygone[3].y -= moveY; /* Test de limitation de variation des dimensions : * si les sommets se "croisent", il ne faut plus modifier les * coordonnees correspondantes */ if( polygone[0].x > polygone[3].x ) { /* croisement sur axe X des 2 sommets 0 et 3 */ polygone[0].x = polygone[3].x = 0; } if( polygone[1].x > polygone[2].x ) { /* croisement sur axe X des 2 sommets 1 et 2 */ polygone[1].x = polygone[2].x = 0; } if( polygone[1].y > polygone[0].y ) { /* croisement sur axe Y des 2 sommets 0 et 1 */ polygone[0].y = polygone[1].y = 0; } if( polygone[2].y > polygone[3].y ) { /* croisement sur axe Y des 2 sommets 2 et 3 */ polygone[2].y = polygone[3].y = 0; } for( ii = 0; ii < 4; ii++ ) { coord[ii].x = polygone[ii].x + padpos.x; coord[ii].y = polygone[ii].y + padpos.y; RotatePoint( &coord[ii], padpos, orient ); } Move_Plume_HPGL( coord[0], 'U' ); Move_Plume_HPGL( coord[1], 'D' ); Move_Plume_HPGL( coord[2], 'D' ); Move_Plume_HPGL( coord[3], 'D' ); Move_Plume_HPGL( coord[0], 'D' ); } Plume_HPGL( 'U' ); } /********************************************************************/ void trace_1_segment_HPGL( int pos_X0, int pos_Y0, int pos_X1, int pos_Y1, int epaisseur ) /********************************************************************/ /* Trace 1 rectangle donne par son axe et son epaisseur (piste rectangulaire) * en mode SKETCH */ { float alpha; /* angle de l'axe du rectangle */ wxSize size; /* coord relatives a l'origine du segment de sa fin */ int dh; /* demi epaisseur du segment compte tenu de la * largeur de la plume */ int dx_rot; /* coord du segment en repere modifie ( size.y_rot etant nul )*/ float sin_alpha, cos_alpha; size.x = pos_X1 - pos_X0; size.y = pos_Y1 - pos_Y0; dh = (epaisseur - (int) pen_diam ) / 2; if( dh < 0 ) { dh = 0; nb_plot_erreur++; Affiche_erreur( nb_plot_erreur ); } if( (dh == 0) || (Plot_Mode == FILAIRE) ) /* Le trace se reduit a 1 trait */ { Move_Plume_HPGL( wxPoint( pos_X0, pos_Y0 ), 'U' ); Move_Plume_HPGL( wxPoint( pos_X1, pos_Y1 ), 'D' ); Plume_HPGL( 'U' ); return; } if( size.x < 0 ) { EXCHG( pos_X0, pos_X1 ); EXCHG( pos_Y0, pos_Y1 ); size.y = -size.y; size.x = -size.x; } if( size.y == 0 ) /* segment horizontal */ { Move_Plume_HPGL( wxPoint( pos_X0, pos_Y0 - dh ), 'U' ); Move_Plume_HPGL( wxPoint( pos_X1, pos_Y1 - dh ), 'D' ); Move_Plume_HPGL( wxPoint( pos_X1, pos_Y1 + dh ), 'D' ); Move_Plume_HPGL( wxPoint( pos_X0, pos_Y0 + dh ), 'D' ); Move_Plume_HPGL( wxPoint( pos_X0, pos_Y0 - dh ), 'D' ); } else if( size.x == 0 ) /* vertical */ { if( size.y < 0 ) dh = -dh; Move_Plume_HPGL( wxPoint( pos_X0 - dh, pos_Y0 ), 'U' ); Move_Plume_HPGL( wxPoint( pos_X1 - dh, pos_Y1 ), 'D' ); Move_Plume_HPGL( wxPoint( pos_X1 + dh, pos_Y1 ), 'D' ); Move_Plume_HPGL( wxPoint( pos_X0 + dh, pos_Y0 ), 'D' ); Move_Plume_HPGL( wxPoint( pos_X0 - dh, pos_Y0 ), 'D' ); } else /* piste inclinee */ { /* On calcule les coord des extremites du rectangle dans le repere * a axe x confondu avec l'axe du rect. puis on revient dans le repere * de trace par 2 rotations inverses * coord : xrot = x*cos + y*sin * yrot = y*cos - x*sin * * avec ici yrot = 0 puisque le segment est horizontal dans le nouveau repere * Transformee inverse : * coord : x = xrot*cos - yrot*sin * y = yrot*cos + xrot*sin */ int dx0, dy0, dx1, dy1; if( size.x == size.y ) /* alpah = 45 degre */ { sin_alpha = cos_alpha = 0.70711; } else if( size.x == -size.y ) /* alpah = -45 degre */ { cos_alpha = 0.70711; sin_alpha = -0.70711; } else { alpha = atan2( (double) size.y, (double) size.x ); sin_alpha = sin( alpha ); cos_alpha = cos( alpha ); } dx_rot = (int) (size.x * cos_alpha + size.y * sin_alpha); /* size.y_rot = (int)(size.y * cos_alpha - size.x * sin_alpha) ; doit etre NULL */ /* calcul du point de coord 0,-dh */ dx0 = (int) ( dh * sin_alpha); dy0 = (int) (-dh * cos_alpha ); Move_Plume_HPGL( wxPoint( pos_X0 + dx0, pos_Y0 + dy0 ), 'U' ); /* calcul du point de coord size.xrot,-dh */ dx1 = (int) (dx_rot * cos_alpha + dh * sin_alpha); dy1 = (int) (-dh * cos_alpha + dx_rot * sin_alpha ); Move_Plume_HPGL( wxPoint( pos_X0 + dx1, pos_Y0 + dy1 ), 'D' ); /* calcul du point de coord size.xrot,+dh */ dx1 = (int) (dx_rot * cos_alpha - dh * sin_alpha); dy1 = (int) (dh * cos_alpha + dx_rot * sin_alpha ); Move_Plume_HPGL( wxPoint( pos_X0 + dx1, pos_Y0 + dy1 ), 'D' ); /* calcul du point de coord 0,+dh */ dx1 = (int) ( -dh * sin_alpha); dy1 = (int) (dh * cos_alpha ); Move_Plume_HPGL( wxPoint( pos_X0 + dx1, pos_Y0 + dy1 ), 'D' ); /* retour au point de depart */ Move_Plume_HPGL( wxPoint( pos_X0 + dx0, pos_Y0 + dy0 ), 'D' ); } Plume_HPGL( 'U' ); }