void CLAYER_TRIANGLES::AddToMiddleContourns( const SHAPE_POLY_SET &aPolySet, float zBot, float zTop, double aBiuTo3Du, bool aInvertFaceDirection ) { wxASSERT( aPolySet.OutlineCount() > 0 ); if( aPolySet.OutlineCount() == 0 ) return; // Calculate an estimation of points to reserve unsigned int nrContournPointsToReserve = 0; for( int i = 0; i < aPolySet.OutlineCount(); ++i ) { const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i ); nrContournPointsToReserve += pathOutline.PointCount(); for( int h = 0; h < aPolySet.HoleCount( i ); ++h ) { const SHAPE_LINE_CHAIN &hole = aPolySet.CHole( i, h ); nrContournPointsToReserve += hole.PointCount(); } } // Request to reserve more space m_layer_middle_contourns_quads->Reserve_More( nrContournPointsToReserve * 2, true ); #pragma omp parallel for for( signed int i = 0; i < aPolySet.OutlineCount(); ++i ) { // Add outline const SHAPE_LINE_CHAIN& pathOutline = aPolySet.COutline( i ); AddToMiddleContourns( pathOutline, zBot, zTop, aBiuTo3Du, aInvertFaceDirection ); // Add holes for this outline for( int h = 0; h < aPolySet.HoleCount( i ); ++h ) { const SHAPE_LINE_CHAIN &hole = aPolySet.CHole( i, h ); AddToMiddleContourns( hole, zBot, zTop, aBiuTo3Du, aInvertFaceDirection ); } } }
/* Build a pad outline as non filled polygon, to draw pads on silkscreen layer * Used only to draw pads outlines on silkscreen layers. */ void EDA_3D_CANVAS::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad, SHAPE_POLY_SET& aCornerBuffer, int aWidth, int aCircleToSegmentsCount, double aCorrectionFactor ) { if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring { TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(), aPad->GetSize().x / 2, aCircleToSegmentsCount, aWidth ); return; } // For other shapes, draw polygon outlines SHAPE_POLY_SET corners; aPad->BuildPadShapePolygon( corners, wxSize( 0, 0 ), aCircleToSegmentsCount, aCorrectionFactor ); // Add outlines as thick segments in polygon buffer const SHAPE_LINE_CHAIN& path = corners.COutline( 0 ); for( int ii = 0; ii < path.PointCount(); ii++ ) { const VECTOR2I& a = path.CPoint( ii ); const VECTOR2I& b = path.CPoint( ii + 1 ); TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ), wxPoint( b.x, b.y ), aCircleToSegmentsCount, aWidth ); } }
void DXF_PLOTTER::ThickSegment( const wxPoint& aStart, const wxPoint& aEnd, int aWidth, EDA_DRAW_MODE_T aPlotMode, void* aData ) { if( aPlotMode == SKETCH ) { std::vector<wxPoint> cornerList; SHAPE_POLY_SET outlineBuffer; TransformOvalClearanceToPolygon( outlineBuffer, aStart, aEnd, aWidth, 32 , 1.0 ); const SHAPE_LINE_CHAIN& path = outlineBuffer.COutline(0 ); for( int jj = 0; jj < path.PointCount(); jj++ ) cornerList.push_back( wxPoint( path.CPoint( jj ).x , path.CPoint( jj ).y ) ); // Ensure the polygon is closed if( cornerList[0] != cornerList[cornerList.size() - 1] ) cornerList.push_back( cornerList[0] ); PlotPoly( cornerList, NO_FILL ); } else { MoveTo( aStart ); FinishTo( aEnd ); } }
void CINFO3D_VISU::buildPadShapeThickOutlineAsPolygon( const D_PAD* aPad, SHAPE_POLY_SET& aCornerBuffer, int aWidth ) const { if( aPad->GetShape() == PAD_SHAPE_CIRCLE ) // Draw a ring { unsigned int nr_sides_per_circle = GetNrSegmentsCircle( ( aPad->GetSize().x / 2 + aWidth / 2 ) * 2 ); TransformRingToPolygon( aCornerBuffer, aPad->ShapePos(), aPad->GetSize().x / 2, nr_sides_per_circle, aWidth ); return; } // For other shapes, draw polygon outlines SHAPE_POLY_SET corners; unsigned int nr_sides_per_circle = GetNrSegmentsCircle( glm::min( aPad->GetSize().x, aPad->GetSize().y) ); buildPadShapePolygon( aPad, corners, wxSize( 0, 0 ), nr_sides_per_circle, GetCircleCorrectionFactor( nr_sides_per_circle ) ); // Add outlines as thick segments in polygon buffer const SHAPE_LINE_CHAIN& path = corners.COutline( 0 ); for( int ii = 0; ii < path.PointCount(); ++ii ) { const VECTOR2I& a = path.CPoint( ii ); const VECTOR2I& b = path.CPoint( ii + 1 ); TransformRoundedEndsSegmentToPolygon( aCornerBuffer, wxPoint( a.x, a.y ), wxPoint( b.x, b.y ), nr_sides_per_circle, aWidth ); } }
bool D_PAD::HitTest( const wxPoint& aPosition ) const { int dx, dy; wxPoint shape_pos = ShapePos(); wxPoint delta = aPosition - shape_pos; // first test: a test point must be inside a minimum sized bounding circle. int radius = GetBoundingRadius(); if( ( abs( delta.x ) > radius ) || ( abs( delta.y ) > radius ) ) return false; dx = m_Size.x >> 1; // dx also is the radius for rounded pads dy = m_Size.y >> 1; switch( GetShape() ) { case PAD_SHAPE_CIRCLE: if( KiROUND( EuclideanNorm( delta ) ) <= dx ) return true; break; case PAD_SHAPE_TRAPEZOID: { wxPoint poly[4]; BuildPadPolygon( poly, wxSize(0,0), 0 ); RotatePoint( &delta, -m_Orient ); return TestPointInsidePolygon( poly, 4, delta ); } case PAD_SHAPE_OVAL: { RotatePoint( &delta, -m_Orient ); // An oval pad has the same shape as a segment with rounded ends // After rotation, the test point is relative to an horizontal pad int dist; wxPoint offset; if( dy > dx ) // shape is a vertical oval { offset.y = dy - dx; dist = dx; } else //if( dy <= dx ) shape is an horizontal oval { offset.x = dy - dx; dist = dy; } return TestSegmentHit( delta, - offset, offset, dist ); } break; case PAD_SHAPE_RECT: RotatePoint( &delta, -m_Orient ); if( (abs( delta.x ) <= dx ) && (abs( delta.y ) <= dy) ) return true; break; case PAD_SHAPE_ROUNDRECT: { // Check for hit in polygon SHAPE_POLY_SET outline; const int segmentToCircleCount = 32; TransformRoundRectToPolygon( outline, wxPoint(0,0), GetSize(), m_Orient, GetRoundRectCornerRadius(), segmentToCircleCount ); const SHAPE_LINE_CHAIN &poly = outline.COutline( 0 ); return TestPointInsidePolygon( (const wxPoint*)&poly.CPoint(0), poly.PointCount(), delta ); } break; case PAD_SHAPE_CUSTOM: // Check for hit in polygon RotatePoint( &delta, -m_Orient ); if( m_customShapeAsPolygon.OutlineCount() ) { const SHAPE_LINE_CHAIN& poly = m_customShapeAsPolygon.COutline( 0 ); return TestPointInsidePolygon( (const wxPoint*)&poly.CPoint(0), poly.PointCount(), delta ); } break; } return false; }
/* test DRC between 2 pads. * this function can be also used to test DRC between a pad and a hole, * because a hole is like a round or oval pad. */ bool DRC::checkClearancePadToPad( D_PAD* aRefPad, D_PAD* aPad ) { int dist; double pad_angle; // Get the clearance between the 2 pads. this is the min distance between aRefPad and aPad int dist_min = aRefPad->GetClearance( aPad ); // relativePadPos is the aPad shape position relative to the aRefPad shape position wxPoint relativePadPos = aPad->ShapePos() - aRefPad->ShapePos(); dist = KiROUND( EuclideanNorm( relativePadPos ) ); // Quick test: Clearance is OK if the bounding circles are further away than "dist_min" if( (dist - aRefPad->GetBoundingRadius() - aPad->GetBoundingRadius()) >= dist_min ) return true; /* Here, pads are near and DRC depend on the pad shapes * We must compare distance using a fine shape analysis * Because a circle or oval shape is the easier shape to test, try to have * aRefPad shape type = PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL. * if aRefPad = TRAP. and aPad = RECT, also swap pads * Swap aRefPad and aPad if needed */ bool swap_pads; swap_pads = false; // swap pads to make comparisons easier // Note also a ROUNDRECT pad with a corner radius = r can be considered as // a smaller RECT (size - 2*r) with a clearance increased by r // priority is aRefPad = ROUND then OVAL then RECT/ROUNDRECT then other if( aRefPad->GetShape() != aPad->GetShape() && aRefPad->GetShape() != PAD_SHAPE_CIRCLE ) { // pad ref shape is here oval, rect, roundrect, trapezoid or custom switch( aPad->GetShape() ) { case PAD_SHAPE_CIRCLE: swap_pads = true; break; case PAD_SHAPE_OVAL: swap_pads = true; break; case PAD_SHAPE_RECT: case PAD_SHAPE_ROUNDRECT: if( aRefPad->GetShape() != PAD_SHAPE_OVAL ) swap_pads = true; break; default: break; } } if( swap_pads ) { std::swap( aRefPad, aPad ); relativePadPos = -relativePadPos; } // corners of aRefPad (used only for rect/roundrect/trap pad) wxPoint polyref[4]; // corners of aRefPad (used only for custom pad) SHAPE_POLY_SET polysetref; // corners of aPad (used only for rect/roundrect/trap pad) wxPoint polycompare[4]; // corners of aPad (used only custom pad) SHAPE_POLY_SET polysetcompare; /* Because pad exchange, aRefPad shape is PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL, * if one of the 2 pads was a PAD_SHAPE_CIRCLE or PAD_SHAPE_OVAL. * Therefore, if aRefPad is a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID, * aPad is also a PAD_SHAPE_RECT, PAD_SHAPE_ROUNDRECT or a PAD_SHAPE_TRAPEZOID */ bool diag = true; switch( aRefPad->GetShape() ) { case PAD_SHAPE_CIRCLE: /* One can use checkClearanceSegmToPad to test clearance * aRefPad is like a track segment with a null length and a witdth = GetSize().x */ m_segmLength = 0; m_segmAngle = 0; m_segmEnd.x = m_segmEnd.y = 0; m_padToTestPos = relativePadPos; diag = checkClearanceSegmToPad( aPad, aRefPad->GetSize().x, dist_min ); break; case PAD_SHAPE_TRAPEZOID: case PAD_SHAPE_ROUNDRECT: case PAD_SHAPE_RECT: // pad_angle = pad orient relative to the aRefPad orient pad_angle = aRefPad->GetOrientation() + aPad->GetOrientation(); NORMALIZE_ANGLE_POS( pad_angle ); if( aRefPad->GetShape() == PAD_SHAPE_ROUNDRECT ) { int padRadius = aRefPad->GetRoundRectCornerRadius(); dist_min += padRadius; GetRoundRectCornerCenters( polyref, padRadius, wxPoint( 0, 0 ), aRefPad->GetSize(), aRefPad->GetOrientation() ); } else aRefPad->BuildPadPolygon( polyref, wxSize( 0, 0 ), aRefPad->GetOrientation() ); switch( aPad->GetShape() ) { case PAD_SHAPE_ROUNDRECT: case PAD_SHAPE_RECT: case PAD_SHAPE_TRAPEZOID: if( aPad->GetShape() == PAD_SHAPE_ROUNDRECT ) { int padRadius = aPad->GetRoundRectCornerRadius(); dist_min += padRadius; GetRoundRectCornerCenters( polycompare, padRadius, relativePadPos, aPad->GetSize(), aPad->GetOrientation() ); } else { aPad->BuildPadPolygon( polycompare, wxSize( 0, 0 ), aPad->GetOrientation() ); // Move aPad shape to relativePadPos for( int ii = 0; ii < 4; ii++ ) polycompare[ii] += relativePadPos; } // And now test polygons: if( polysetref.OutlineCount() ) { const SHAPE_LINE_CHAIN& refpoly = polysetref.COutline( 0 ); // And now test polygons: if( !poly2polyDRC( (wxPoint*) &refpoly.CPoint( 0 ), refpoly.PointCount(), polycompare, 4, dist_min ) ) diag = false; } else if( !poly2polyDRC( polyref, 4, polycompare, 4, dist_min ) ) diag = false; break; default: wxLogDebug( wxT( "DRC::checkClearancePadToPad: unexpected pad shape %d" ), aPad->GetShape() ); break; } break; case PAD_SHAPE_OVAL: /* an oval pad is like a track segment */ { /* Create a track segment with same dimensions as the oval aRefPad * and use checkClearanceSegmToPad function to test aPad to aRefPad clearance */ int segm_width; m_segmAngle = aRefPad->GetOrientation(); // Segment orient. if( aRefPad->GetSize().y < aRefPad->GetSize().x ) // Build an horizontal equiv segment { segm_width = aRefPad->GetSize().y; m_segmLength = aRefPad->GetSize().x - aRefPad->GetSize().y; } else // Vertical oval: build an horizontal equiv segment and rotate 90.0 deg { segm_width = aRefPad->GetSize().x; m_segmLength = aRefPad->GetSize().y - aRefPad->GetSize().x; m_segmAngle += 900; } /* the start point must be 0,0 and currently relativePadPos * is relative the center of pad coordinate */ wxPoint segstart; segstart.x = -m_segmLength / 2; // Start point coordinate of the horizontal equivalent segment RotatePoint( &segstart, m_segmAngle ); // actual start point coordinate of the equivalent segment // Calculate segment end position relative to the segment origin m_segmEnd.x = -2 * segstart.x; m_segmEnd.y = -2 * segstart.y; // Recalculate the equivalent segment angle in 0,1 degrees // to prepare a call to checkClearanceSegmToPad() m_segmAngle = ArcTangente( m_segmEnd.y, m_segmEnd.x ); // move pad position relative to the segment origin m_padToTestPos = relativePadPos - segstart; // Use segment to pad check to test the second pad: diag = checkClearanceSegmToPad( aPad, segm_width, dist_min ); break; } default: wxLogDebug( wxT( "DRC::checkClearancePadToPad: unknown pad shape" ) ); break; } return diag; }
bool ZONE_FILLER::fillZoneWithSegments( const ZONE_CONTAINER* aZone, const SHAPE_POLY_SET& aFilledPolys, ZONE_SEGMENT_FILL& aFillSegs ) const { bool success = true; // segments are on something like a grid. Give it a minimal size // to avoid too many segments, and use the m_ZoneMinThickness when (this is usually the case) // the size is > mingrid_size. // This is not perfect, but the actual purpose of this code // is to allow filling zones on a grid, with grid size > m_ZoneMinThickness, // in order to have really a grid. // // Using a user selectable grid size is for future Kicad versions. // For now the area is fully filled. int mingrid_size = Millimeter2iu( 0.05 ); int grid_size = std::max( mingrid_size, aZone->GetMinThickness() ); // Make segments slightly overlapping to ensure a good full filling grid_size -= grid_size/20; // Creates the horizontal segments for ( int index = 0; index < aFilledPolys.OutlineCount(); index++ ) { const SHAPE_LINE_CHAIN& outline0 = aFilledPolys.COutline( index ); success = fillPolygonWithHorizontalSegments( outline0, aFillSegs, grid_size ); if( !success ) break; // Creates the vertical segments. Because the filling algo creates horizontal segments, // to reuse the fillPolygonWithHorizontalSegments function, we rotate the polygons to fill // then fill them, then inverse rotate the result SHAPE_LINE_CHAIN outline90; outline90.Append( outline0 ); // Rotate 90 degrees the outline: for( int ii = 0; ii < outline90.PointCount(); ii++ ) { VECTOR2I& point = outline90.Point( ii ); std::swap( point.x, point.y ); point.y = -point.y; } int first_point = aFillSegs.size(); success = fillPolygonWithHorizontalSegments( outline90, aFillSegs, grid_size ); if( !success ) break; // Rotate -90 degrees the segments: for( unsigned ii = first_point; ii < aFillSegs.size(); ii++ ) { SEG& segm = aFillSegs[ii]; std::swap( segm.A.x, segm.A.y ); std::swap( segm.B.x, segm.B.y ); segm.A.x = - segm.A.x; segm.B.x = - segm.B.x; } } return success; }
void Convert_shape_line_polygon_to_triangles( const SHAPE_POLY_SET &aPolyList, CGENERICCONTAINER2D &aDstContainer, float aBiuTo3DunitsScale , const BOARD_ITEM &aBoardItem ) { unsigned int nOutlines = aPolyList.OutlineCount(); for( unsigned int idx = 0; idx < nOutlines; ++idx ) { const SHAPE_LINE_CHAIN &outlinePath = aPolyList.COutline( idx ); wxASSERT( outlinePath.PointCount() >= 3 ); std::vector<SFVEC2I64> scaledOutline; scaledOutline.resize( outlinePath.PointCount() ); // printf("\nidx: %u\n", idx); // Apply a scale to the points for( unsigned int i = 0; i < (unsigned int)outlinePath.PointCount(); ++i ) { const VECTOR2I& a = outlinePath.CPoint( i ); #ifdef APPLY_EDGE_SHRINK scaledOutline[i] = SFVEC2I64( (glm::int64)a.x * POLY_SCALE_FACT, (glm::int64)a.y * POLY_SCALE_FACT ); #else scaledOutline[i] = SFVEC2I64( (glm::int64)a.x, (glm::int64)a.y ); #endif } #ifdef APPLY_EDGE_SHRINK // Apply a modification to the points EdgeShrink( scaledOutline ); #endif // Copy to a array of pointers std::vector<p2t::Point*> polyline; polyline.resize( outlinePath.PointCount() ); for( unsigned int i = 0; i < (unsigned int)scaledOutline.size(); ++i ) { const SFVEC2I64 &a = scaledOutline[i]; //printf("%lu %lu\n", a.x, a.y); polyline[i] = new p2t::Point( (double)a.x, (double)a.y ); } // Start creating the structured to be triangulated p2t::CDT* cdt = new p2t::CDT( polyline ); // Add holes for this outline unsigned int nHoles = aPolyList.HoleCount( idx ); std::vector< std::vector<p2t::Point*> > polylineHoles; polylineHoles.resize( nHoles ); for( unsigned int idxHole = 0; idxHole < nHoles; ++idxHole ) { const SHAPE_LINE_CHAIN &outlineHoles = aPolyList.CHole( idx, idxHole ); wxASSERT( outlineHoles.PointCount() >= 3 ); std::vector<SFVEC2I64> scaledHole; scaledHole.resize( outlineHoles.PointCount() ); // Apply a scale to the points for( unsigned int i = 0; i < (unsigned int)outlineHoles.PointCount(); ++i ) { const VECTOR2I &h = outlineHoles.CPoint( i ); #ifdef APPLY_EDGE_SHRINK scaledHole[i] = SFVEC2I64( (glm::int64)h.x * POLY_SCALE_FACT, (glm::int64)h.y * POLY_SCALE_FACT ); #else scaledHole[i] = SFVEC2I64( (glm::int64)h.x, (glm::int64)h.y ); #endif } #ifdef APPLY_EDGE_SHRINK // Apply a modification to the points EdgeShrink( scaledHole ); #endif // Resize and reserve space polylineHoles[idxHole].resize( outlineHoles.PointCount() ); for( unsigned int i = 0; i < (unsigned int)outlineHoles.PointCount(); ++i ) { const SFVEC2I64 &h = scaledHole[i]; polylineHoles[idxHole][i] = new p2t::Point( h.x, h.y ); } cdt->AddHole( polylineHoles[idxHole] ); } // Triangulate cdt->Triangulate(); // Hint: if you find any crashes on the triangulation poly2tri library, // you can use the following site to debug the points and it will mark // the errors in the polygon: // http://r3mi.github.io/poly2tri.js/ // Get and add triangles std::vector<p2t::Triangle*> triangles; triangles = cdt->GetTriangles(); #ifdef APPLY_EDGE_SHRINK const double conver_d = (double)aBiuTo3DunitsScale * POLY_SCALE_FACT_INVERSE; #else const double conver_d = (double)aBiuTo3DunitsScale; #endif for( unsigned int i = 0; i < triangles.size(); ++i ) { p2t::Triangle& t = *triangles[i]; p2t::Point& a = *t.GetPoint( 0 ); p2t::Point& b = *t.GetPoint( 1 ); p2t::Point& c = *t.GetPoint( 2 ); aDstContainer.Add( new CTRIANGLE2D( SFVEC2F( a.x * conver_d, -a.y * conver_d ), SFVEC2F( b.x * conver_d, -b.y * conver_d ), SFVEC2F( c.x * conver_d, -c.y * conver_d ), aBoardItem ) ); } // Delete created data delete cdt; // Free points FreeClear(polyline); for( unsigned int idxHole = 0; idxHole < nHoles; ++idxHole ) { FreeClear( polylineHoles[idxHole] ); } } }
bool D_PAD::GetBestAnchorPosition( VECTOR2I& aPos ) { SHAPE_POLY_SET poly; if( !buildCustomPadPolygon( &poly, ARC_LOW_DEF ) ) return false; const int minSteps = 10; const int maxSteps = 50; int stepsX, stepsY; auto bbox = poly.BBox(); if( bbox.GetWidth() < bbox.GetHeight() ) { stepsX = minSteps; stepsY = minSteps * (double) bbox.GetHeight() / (double )(bbox.GetWidth() + 1); } else { stepsY = minSteps; stepsX = minSteps * (double) bbox.GetWidth() / (double )(bbox.GetHeight() + 1); } stepsX = std::max(minSteps, std::min( maxSteps, stepsX ) ); stepsY = std::max(minSteps, std::min( maxSteps, stepsY ) ); auto center = bbox.Centre(); auto minDist = std::numeric_limits<int64_t>::max(); int64_t minDistEdge; if( GetAnchorPadShape() == PAD_SHAPE_CIRCLE ) { minDistEdge = GetSize().x; } else { minDistEdge = std::max( GetSize().x, GetSize().y ); } OPT<VECTOR2I> bestAnchor( []()->OPT<VECTOR2I> { return NULLOPT; }() ); for ( int y = 0; y < stepsY ; y++ ) { for ( int x = 0; x < stepsX; x++ ) { VECTOR2I p = bbox.GetPosition(); p.x += rescale( x, bbox.GetWidth(), (stepsX - 1) ); p.y += rescale( y, bbox.GetHeight(), (stepsY - 1) ); if ( poly.Contains(p) ) { auto dist = (center - p).EuclideanNorm(); auto distEdge = poly.COutline(0).Distance( p, true ); if ( distEdge >= minDistEdge ) { if ( dist < minDist ) { bestAnchor = p; minDist = dist; } } } } } if ( bestAnchor ) { aPos = *bestAnchor; return true; } return false; }
/** * DXF polygon: doesn't fill it but at least it close the filled ones * DXF does not know thick outline. * It does not know thhick segments, therefore filled polygons with thick outline * are converted to inflated polygon by aWidth/2 */ void DXF_PLOTTER::PlotPoly( const std::vector<wxPoint>& aCornerList, FILL_T aFill, int aWidth) { if( aCornerList.size() <= 1 ) return; unsigned last = aCornerList.size() - 1; // Plot outlines with lines (thickness = 0) to define the polygon if( aWidth <= 0 ) { MoveTo( aCornerList[0] ); for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) LineTo( aCornerList[ii] ); // Close polygon if 'fill' requested if( aFill ) { if( aCornerList[last] != aCornerList[0] ) LineTo( aCornerList[0] ); } PenFinish(); return; } // if the polygon outline has thickness, and is not filled // (i.e. is a polyline) plot outlines with thick segments if( aWidth > 0 && !aFill ) { MoveTo( aCornerList[0] ); for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) ThickSegment( aCornerList[ii-1], aCornerList[ii], aWidth, FILLED ); return; } // The polygon outline has thickness, and is filled // Build and plot the polygon which contains the initial // polygon and its thick outline SHAPE_POLY_SET bufferOutline; SHAPE_POLY_SET bufferPolybase; const int circleToSegmentsCount = 16; bufferPolybase.NewOutline(); // enter outline as polygon: for( unsigned ii = 1; ii < aCornerList.size(); ii++ ) { TransformRoundedEndsSegmentToPolygon( bufferOutline, aCornerList[ii-1], aCornerList[ii], circleToSegmentsCount, aWidth ); } // enter the initial polygon: for( unsigned ii = 0; ii < aCornerList.size(); ii++ ) { bufferPolybase.Append( aCornerList[ii] ); } // Merge polygons to build the polygon which contains the initial // polygon and its thick outline bufferPolybase.BooleanAdd( bufferOutline ); // create the outline which contains thick outline bufferPolybase.Fracture(); if( bufferPolybase.OutlineCount() < 1 ) // should not happen return; const SHAPE_LINE_CHAIN& path = bufferPolybase.COutline( 0 ); if( path.PointCount() < 2 ) // should not happen return; // Now, output the final polygon to DXF file: last = path.PointCount() - 1; VECTOR2I point = path.CPoint( 0 ); wxPoint startPoint( point.x, point.y ); MoveTo( startPoint ); for( int ii = 1; ii < path.PointCount(); ii++ ) { point = path.CPoint( ii ); LineTo( wxPoint( point.x, point.y ) ); } // Close polygon, if needed point = path.CPoint( last ); wxPoint endPoint( point.x, point.y ); if( endPoint != startPoint ) LineTo( startPoint ); PenFinish(); }
void C3D_RENDER_OGL_LEGACY::reload() { m_reloadRequested = false; ogl_free_all_display_lists(); COBJECT2D_STATS::Instance().ResetStats(); m_settings.InitSettings(); SFVEC3F camera_pos = m_settings.GetBoardCenter3DU(); m_settings.CameraGet().SetBoardLookAtPos( camera_pos ); // Create Board // ///////////////////////////////////////////////////////////////////////// printf("Create board...\n"); CCONTAINER2D boardContainer; Convert_shape_line_polygon_to_triangles( m_settings.GetBoardPoly(), boardContainer, m_settings.BiuTo3Dunits(), (const BOARD_ITEM &)*m_settings.GetBoard() ); const LIST_OBJECT2D listBoardObject2d = boardContainer.GetList(); if( listBoardObject2d.size() > 0 ) { /* float layer_z_top = m_settings.GetLayerBottomZpos3DU( F_Cu ); float layer_z_bot = m_settings.GetLayerBottomZpos3DU( B_Cu ); */ float layer_z_top = m_settings.GetLayerBottomZpos3DU( B_Mask ); float layer_z_bot = m_settings.GetLayerTopZpos3DU( B_Mask ); CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( listBoardObject2d.size() ); for( LIST_OBJECT2D::const_iterator itemOnLayer = listBoardObject2d.begin(); itemOnLayer != listBoardObject2d.end(); itemOnLayer++ ) { const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer); wxASSERT( object2d_A->GetObjectType() == OBJ2D_TRIANGLE ); const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A; const SFVEC2F &v1 = tri->GetP1(); const SFVEC2F &v2 = tri->GetP2(); const SFVEC2F &v3 = tri->GetP3(); add_triangle_top_bot( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot ); } const SHAPE_POLY_SET boardPoly = m_settings.GetBoardPoly(); SHAPE_POLY_SET boardPolyCopy = boardPoly; boardPolyCopy.Simplify( SHAPE_POLY_SET::PM_FAST ); if( boardPolyCopy.OutlineCount() == 1 ) { const SHAPE_LINE_CHAIN& outlinePath = boardPolyCopy.COutline( 0 ); std::vector< SFVEC2F > contournPoints; contournPoints.clear(); contournPoints.reserve( outlinePath.PointCount() + 2 ); for( unsigned int i = 0; i < (unsigned int)outlinePath.PointCount(); ++i ) { const VECTOR2I& v = outlinePath.CPoint( i ); contournPoints.push_back( SFVEC2F( v.x * m_settings.BiuTo3Dunits(), -v.y * m_settings.BiuTo3Dunits() ) ); } contournPoints.push_back( contournPoints[0] ); if( contournPoints.size() > 4 ) { // Calculate normals of each segment of the contourn std::vector< SFVEC2F > contournNormals; contournNormals.clear(); contournNormals.reserve( contournPoints.size() ); for( unsigned int i = 0; i < ( contournPoints.size() - 1 ); ++i ) { const SFVEC2F &v0 = contournPoints[i + 0]; const SFVEC2F &v1 = contournPoints[i + 1]; SFVEC2F n = glm::normalize( v1 - v0 ); contournNormals.push_back( SFVEC2F( -n.y, n.x ) ); } SFVEC2F lastNormal = contournNormals[contournPoints.size() - 2]; for( unsigned int i = 0; i < ( contournPoints.size() - 1 ); ++i ) { const SFVEC2F &v0 = contournPoints[i + 0]; const SFVEC2F &v1 = contournPoints[i + 1]; layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_top ) ), SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_top ) ), SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_bot ) ), SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_bot ) ) ); SFVEC2F n0 = contournNormals[i]; if( glm::dot( n0, lastNormal ) > 0.5f ) n0 += lastNormal; else n0 += contournNormals[i]; const SFVEC2F &nextNormal = contournNormals[ (i + 1) % (contournPoints.size() - 1) ]; SFVEC2F n1 = contournNormals[i]; if( glm::dot( n1, nextNormal ) > 0.5f ) n1 += nextNormal; else n1 += contournNormals[i]; n0 = glm::normalize( n0 ); n1 = glm::normalize( n1 ); const SFVEC3F n3d0 = SFVEC3F( n0.x, n0.y, 0.0f ); const SFVEC3F n3d1 = SFVEC3F( n1.x, n1.y, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d0, n3d1, n3d1, n3d0 ); lastNormal = contournNormals[i]; /* const SFVEC2F n0 = glm::normalize( v0 - center ); const SFVEC2F n1 = glm::normalize( v1 - center ); const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f ); const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z );*/ } } contournPoints.clear(); } m_ogl_disp_list_board = new CLAYERS_OGL_DISP_LISTS( *layerTriangles, m_ogl_circle_texture, SFVEC3F(0.65f,0.55f,0.05f) ); delete layerTriangles; } float calc_sides_min_factor = (float)( 10.0 * IU_PER_MILS * m_settings.BiuTo3Dunits() ); float calc_sides_max_factor = (float)( 1000.0 * IU_PER_MILS * m_settings.BiuTo3Dunits() ); // Add layers maps (except B_Mask and F_Mask) // ///////////////////////////////////////////////////////////////////////// printf("Add layers maps...\n"); for( MAP_CONTAINER_2D::const_iterator it = m_settings.GetMapLayers().begin(); it != m_settings.GetMapLayers().end(); it++ ) { LAYER_ID layer_id = static_cast<LAYER_ID>(it->first); if( !m_settings.Is3DLayerEnabled( layer_id ) ) continue; const CBVHCONTAINER2D *container2d = static_cast<const CBVHCONTAINER2D *>(it->second); const LIST_OBJECT2D listObject2d = container2d->GetList(); if( listObject2d.size() == 0 ) continue; //CMATERIAL *materialLayer = &m_materials.m_SilkS; SFVEC3F layerColor = SFVEC3F( 0.3f, 0.4f, 0.5f ); float layer_z_bot = m_settings.GetLayerBottomZpos3DU( layer_id ); float layer_z_top = m_settings.GetLayerTopZpos3DU( layer_id ); if( layer_z_top < layer_z_bot ) { float tmpFloat = layer_z_bot; layer_z_bot = layer_z_top; layer_z_top = tmpFloat; } layer_z_bot -= m_settings.GetNonCopperLayerThickness3DU(); layer_z_top += m_settings.GetNonCopperLayerThickness3DU(); if( m_settings.GetFlag( FL_USE_REALISTIC_MODE ) ) { switch( layer_id ) { case B_Adhes: case F_Adhes: break; case B_Paste: case F_Paste: // materialLayer = &m_materials.m_Paste; break; case B_SilkS: case F_SilkS: // materialLayer = &m_materials.m_SilkS; // layerColor = g_silkscreenColor; break; case Dwgs_User: case Cmts_User: case Eco1_User: case Eco2_User: case Edge_Cuts: case Margin: break; case B_CrtYd: case F_CrtYd: break; case B_Fab: case F_Fab: break; default: //materialLayer = &m_materials.m_Copper; //layerColor = g_copperColor; break; } } else { layerColor = m_settings.GetLayerColor( layer_id ); } // Calculate an estiation for then nr of triangles based on the nr of objects unsigned int nrTrianglesEstimation = listObject2d.size() * 8; CLAYER_TRIANGLES *layerTriangles = new CLAYER_TRIANGLES( nrTrianglesEstimation ); m_triangles[layer_id] = layerTriangles; for( LIST_OBJECT2D::const_iterator itemOnLayer = listObject2d.begin(); itemOnLayer != listObject2d.end(); itemOnLayer++ ) { const COBJECT2D *object2d_A = static_cast<const COBJECT2D *>(*itemOnLayer); switch( object2d_A->GetObjectType() ) { case OBJ2D_FILLED_CIRCLE: { const CFILLEDCIRCLE2D *filledCircle = (const CFILLEDCIRCLE2D *)object2d_A; const SFVEC2F ¢er = filledCircle->GetCenter(); float radius = filledCircle->GetRadius() * 2.0f; // Double because the render triangle float radiusSquared = radius * radius; const float f = (sqrtf(2.0f) / 2.0f) * radius * 0.9;// * texture_factor; layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, layer_z_top ), SFVEC3F( center.x - f, center.y, layer_z_top ), SFVEC3F( center.x, center.y - f, layer_z_top ) ); layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, layer_z_top ), SFVEC3F( center.x + f, center.y, layer_z_top ), SFVEC3F( center.x, center.y + f, layer_z_top ) ); layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x - f, center.y, layer_z_bot ), SFVEC3F( center.x + f, center.y, layer_z_bot ), SFVEC3F( center.x, center.y - f, layer_z_bot ) ); layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( center.x + f, center.y, layer_z_bot ), SFVEC3F( center.x - f, center.y, layer_z_bot ), SFVEC3F( center.x, center.y + f, layer_z_bot ) ); unsigned int nr_sides_per_circle = (unsigned int)mapf( radiusSquared, calc_sides_min_factor, calc_sides_max_factor, 24.0f, 256.0f ); wxASSERT( nr_sides_per_circle >= 24 ); // Normal radius for the circle radius = filledCircle->GetRadius(); std::vector< SFVEC2F > contournPoints; contournPoints.clear(); contournPoints.reserve( nr_sides_per_circle + 2 ); int delta = 3600 / nr_sides_per_circle; for( int ii = 0; ii < 3600; ii += delta ) { const SFVEC2F rotatedDir = glm::rotate( SFVEC2F( 0.0f, 1.0f ), (float)ii * 2.0f * 3.14f / 3600.0f ); contournPoints.push_back( SFVEC2F( center.x - rotatedDir.y * radius, center.y + rotatedDir.x * radius ) ); } contournPoints.push_back( contournPoints[0] ); if( contournPoints.size() > 1 ) { for( unsigned int i = 0; i < ( contournPoints.size() - 1 ); ++i ) { const SFVEC2F &v0 = contournPoints[i + 0]; const SFVEC2F &v1 = contournPoints[i + 1]; layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_bot ) ), SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_bot ) ), SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_top ) ), SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_top ) ) ); const SFVEC2F n0 = glm::normalize( v0 - center ); const SFVEC2F n1 = glm::normalize( v1 - center ); const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f ); const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z ); } } contournPoints.clear(); } break; case OBJ2D_DUMMYBLOCK: { } break; case OBJ2D_POLYGON4PT: { const CPOLYGON4PTS2D *poly = (const CPOLYGON4PTS2D *)object2d_A; const SFVEC2F &v0 = poly->GetV0(); const SFVEC2F &v1 = poly->GetV1(); const SFVEC2F &v2 = poly->GetV2(); const SFVEC2F &v3 = poly->GetV3(); add_triangle_top_bot( layerTriangles, v0, v2, v1, layer_z_top, layer_z_bot ); add_triangle_top_bot( layerTriangles, v2, v0, v3, layer_z_top, layer_z_bot ); const SFVEC2F &n0 = poly->GetN0(); const SFVEC2F &n1 = poly->GetN1(); const SFVEC2F &n2 = poly->GetN2(); const SFVEC2F &n3 = poly->GetN3(); const SFVEC3F n3d0 = SFVEC3F(-n0.y, n0.x, 0.0f ); const SFVEC3F n3d1 = SFVEC3F(-n1.y, n1.x, 0.0f ); const SFVEC3F n3d2 = SFVEC3F(-n2.y, n2.x, 0.0f ); const SFVEC3F n3d3 = SFVEC3F(-n3.y, n3.x, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_bot ), SFVEC3F( v1.x, v1.y, layer_z_bot ), SFVEC3F( v1.x, v1.y, layer_z_top ), SFVEC3F( v0.x, v0.y, layer_z_top ) ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d0, n3d0, n3d0, n3d0 ); layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v2.x, v2.y, layer_z_top ), SFVEC3F( v1.x, v1.y, layer_z_top ), SFVEC3F( v1.x, v1.y, layer_z_bot ), SFVEC3F( v2.x, v2.y, layer_z_bot ) ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d1, n3d1, n3d1, n3d1 ); layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v3.x, v3.y, layer_z_top ), SFVEC3F( v2.x, v2.y, layer_z_top ), SFVEC3F( v2.x, v2.y, layer_z_bot ), SFVEC3F( v3.x, v3.y, layer_z_bot ) ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d2, n3d2, n3d2, n3d2 ); layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_top ), SFVEC3F( v3.x, v3.y, layer_z_top ), SFVEC3F( v3.x, v3.y, layer_z_bot ), SFVEC3F( v0.x, v0.y, layer_z_bot ) ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n3d3, n3d3, n3d3, n3d3 ); } break; case OBJ2D_RING: { const CRING2D *ring = (const CRING2D *)object2d_A; const SFVEC2F ¢er = ring->GetCenter(); float inner = ring->GetInnerRadius(); float outer = ring->GetOuterRadius(); unsigned int nr_sides_per_circle = (unsigned int)mapf( outer, calc_sides_min_factor, calc_sides_max_factor, 24.0f, 256.0f ); wxASSERT( nr_sides_per_circle >= 24 ); std::vector< SFVEC2F > innerContour; std::vector< SFVEC2F > outerContour; innerContour.clear(); innerContour.reserve( nr_sides_per_circle + 2 ); outerContour.clear(); outerContour.reserve( nr_sides_per_circle + 2 ); int delta = 3600 / nr_sides_per_circle; for( int ii = 0; ii < 3600; ii += delta ) { const SFVEC2F rotatedDir = glm::rotate( SFVEC2F( 0.0f, 1.0f), (float) ii * 2.0f * 3.14f / 3600.0f ); innerContour.push_back( SFVEC2F( center.x - rotatedDir.y * inner, center.y + rotatedDir.x * inner ) ); outerContour.push_back( SFVEC2F( center.x - rotatedDir.y * outer, center.y + rotatedDir.x * outer ) ); } innerContour.push_back( innerContour[0] ); outerContour.push_back( outerContour[0] ); wxASSERT( innerContour.size() == outerContour.size() ); for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i ) { const SFVEC2F &vi0 = innerContour[i + 0]; const SFVEC2F &vi1 = innerContour[i + 1]; const SFVEC2F &vo0 = outerContour[i + 0]; const SFVEC2F &vo1 = outerContour[i + 1]; layerTriangles->m_layer_top_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, layer_z_top ), SFVEC3F( vi0.x, vi0.y, layer_z_top ), SFVEC3F( vo0.x, vo0.y, layer_z_top ), SFVEC3F( vo1.x, vo1.y, layer_z_top ) ); layerTriangles->m_layer_bot_triangles->AddQuad( SFVEC3F( vi1.x, vi1.y, layer_z_bot ), SFVEC3F( vo1.x, vo1.y, layer_z_bot ), SFVEC3F( vo0.x, vo0.y, layer_z_bot ), SFVEC3F( vi0.x, vi0.y, layer_z_bot ) ); } for( unsigned int i = 0; i < ( innerContour.size() - 1 ); ++i ) { const SFVEC2F &v0 = innerContour[i + 0]; const SFVEC2F &v1 = innerContour[i + 1]; layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_bot ) ), SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_bot ) ), SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_top ) ), SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_top ) ) ); const SFVEC2F n0 = glm::normalize( v0 - center ); const SFVEC2F n1 = glm::normalize( v1 - center ); const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f ); const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z ); } for( unsigned int i = 0; i < ( outerContour.size() - 1 ); ++i ) { const SFVEC2F &v0 = outerContour[i + 0]; const SFVEC2F &v1 = outerContour[i + 1]; layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, NextFloatUp( layer_z_bot ) ), SFVEC3F( v1.x, v1.y, NextFloatUp( layer_z_bot ) ), SFVEC3F( v1.x, v1.y, NextFloatDown( layer_z_top ) ), SFVEC3F( v0.x, v0.y, NextFloatDown( layer_z_top ) ) ); const SFVEC2F n0 = glm::normalize( v0 - center ); const SFVEC2F n1 = glm::normalize( v1 - center ); const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f ); const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z ); } } break; case OBJ2D_TRIANGLE: { const CTRIANGLE2D *tri = (const CTRIANGLE2D *)object2d_A; const SFVEC2F &v1 = tri->GetP1(); const SFVEC2F &v2 = tri->GetP2(); const SFVEC2F &v3 = tri->GetP3(); add_triangle_top_bot( layerTriangles, v1, v2, v3, layer_z_top, layer_z_bot ); } break; case OBJ2D_ROUNDSEG: { const CROUNDSEGMENT2D &roundSeg = (const CROUNDSEGMENT2D &) *object2d_A; unsigned int nr_sides_per_circle = (unsigned int)mapf( roundSeg.GetWidth(), calc_sides_min_factor, calc_sides_max_factor, 24.0f, 256.0f ); wxASSERT( nr_sides_per_circle >= 24 ); SFVEC2F leftStart = roundSeg.GetLeftStar(); SFVEC2F leftEnd = roundSeg.GetLeftEnd(); SFVEC2F leftDir = roundSeg.GetLeftDir(); SFVEC2F rightStart = roundSeg.GetRightStar(); SFVEC2F rightEnd = roundSeg.GetRightEnd(); SFVEC2F rightDir = roundSeg.GetRightDir(); float radius = roundSeg.GetRadius(); SFVEC2F start = roundSeg.GetStart(); SFVEC2F end = roundSeg.GetEnd(); float texture_factor = (12.0f/(float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f; float texture_factorF= ( 4.0f/(float)SIZE_OF_CIRCLE_TEXTURE) + 1.0f; const float radius_of_the_square = sqrtf( roundSeg.GetRadiusSquared() * 2.0f ); const float radius_triangle_factor = (radius_of_the_square - radius) / radius; const SFVEC2F factorS = SFVEC2F( -rightDir.y * radius * radius_triangle_factor, rightDir.x * radius * radius_triangle_factor ); const SFVEC2F factorE = SFVEC2F( -leftDir.y * radius * radius_triangle_factor, leftDir.x * radius * radius_triangle_factor ); // Top end segment triangles layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( rightEnd.x + texture_factor * factorS.x, rightEnd.y + texture_factor * factorS.y, layer_z_top ), SFVEC3F( leftStart.x + texture_factor * factorE.x, leftStart.y + texture_factor * factorE.y, layer_z_top ), SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf(2.0f), start.y - texture_factorF * leftDir.y * radius * sqrtf(2.0f), layer_z_top ) ); layerTriangles->m_layer_top_segment_ends->AddTriangle( SFVEC3F( leftEnd.x + texture_factor * factorE.x, leftEnd.y + texture_factor * factorE.y, layer_z_top ), SFVEC3F( rightStart.x + texture_factor * factorS.x, rightStart.y + texture_factor * factorS.y, layer_z_top ), SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf(2.0f), end.y - texture_factorF * rightDir.y * radius * sqrtf(2.0f), layer_z_top ) ); // Bot end segment triangles layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( leftStart.x + texture_factor * factorE.x, leftStart.y + texture_factor * factorE.y, layer_z_bot ), SFVEC3F( rightEnd.x + texture_factor * factorS.x, rightEnd.y + texture_factor * factorS.y, layer_z_bot ), SFVEC3F( start.x - texture_factorF * leftDir.x * radius * sqrtf(2.0f), start.y - texture_factorF * leftDir.y * radius * sqrtf(2.0f), layer_z_bot ) ); layerTriangles->m_layer_bot_segment_ends->AddTriangle( SFVEC3F( rightStart.x + texture_factor * factorS.x, rightStart.y + texture_factor * factorS.y, layer_z_bot ), SFVEC3F( leftEnd.x + texture_factor * factorE.x, leftEnd.y + texture_factor * factorE.y, layer_z_bot ), SFVEC3F( end.x - texture_factorF * rightDir.x * radius * sqrtf(2.0f), end.y - texture_factorF * rightDir.y * radius * sqrtf(2.0f), layer_z_bot ) ); // Segment top and bot planes layerTriangles->m_layer_top_triangles->AddQuad( SFVEC3F( rightEnd.x, rightEnd.y, layer_z_top ), SFVEC3F( rightStart.x, rightStart.y, layer_z_top ), SFVEC3F( leftEnd.x, leftEnd.y, layer_z_top ), SFVEC3F( leftStart.x, leftStart.y, layer_z_top ) ); layerTriangles->m_layer_bot_triangles->AddQuad( SFVEC3F( rightEnd.x, rightEnd.y, layer_z_bot ), SFVEC3F( leftStart.x, leftStart.y, layer_z_bot ), SFVEC3F( leftEnd.x, leftEnd.y, layer_z_bot ), SFVEC3F( rightStart.x, rightStart.y, layer_z_bot ) ); // Middle contourns (two sides of the segment) layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( leftStart.x, leftStart.y, layer_z_top ), SFVEC3F( leftEnd.x, leftEnd.y, layer_z_top ), SFVEC3F( leftEnd.x, leftEnd.y, layer_z_bot ), SFVEC3F( leftStart.x, leftStart.y, layer_z_bot ) ); const SFVEC3F leftNormal = SFVEC3F( -leftDir.y, leftDir.x, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( leftNormal, leftNormal, leftNormal, leftNormal ); layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( rightStart.x, rightStart.y, layer_z_top ), SFVEC3F( rightEnd.x, rightEnd.y, layer_z_top ), SFVEC3F( rightEnd.x, rightEnd.y, layer_z_bot ), SFVEC3F( rightStart.x, rightStart.y, layer_z_bot ) ); const SFVEC3F rightNormal = SFVEC3F( -rightDir.y, rightDir.x, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( rightNormal, rightNormal, rightNormal, rightNormal ); // Compute the outlines of the segment, and creates a polygon // add right rounded end: std::vector< SFVEC2F > roundedEndPointsStart; std::vector< SFVEC2F > roundedEndPointsEnd; roundedEndPointsStart.clear(); roundedEndPointsStart.reserve( nr_sides_per_circle + 2 ); roundedEndPointsEnd.clear(); roundedEndPointsEnd.reserve( nr_sides_per_circle + 2 ); roundedEndPointsStart.push_back( SFVEC2F( leftStart.x, leftStart.y ) ); roundedEndPointsEnd.push_back( SFVEC2F( leftEnd.x, leftEnd.y ) ); int delta = 3600 / nr_sides_per_circle; for( int ii = delta; ii < 1800; ii += delta ) { const SFVEC2F rotatedDirL = glm::rotate( leftDir, (float) ii * 2.0f * 3.14f / 3600.0f ); const SFVEC2F rotatedDirR = glm::rotate( rightDir, (float)(1800 - ii) * 2.0f * 3.14f / 3600.0f ); roundedEndPointsStart.push_back( SFVEC2F( start.x - rotatedDirL.y * radius, start.y + rotatedDirL.x * radius ) ); roundedEndPointsEnd.push_back( SFVEC2F( end.x - rotatedDirR.y * radius, end.y + rotatedDirR.x * radius ) ); } roundedEndPointsStart.push_back( SFVEC2F( rightEnd.x, rightEnd.y ) ); roundedEndPointsEnd.push_back( SFVEC2F( rightStart.x, rightStart.y ) ); if( roundedEndPointsStart.size() > 1 ) { for( unsigned int i = 0; i < ( roundedEndPointsStart.size() - 1 ); ++i ) { const SFVEC2F &v0 = roundedEndPointsStart[i + 0]; const SFVEC2F &v1 = roundedEndPointsStart[i + 1]; layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_bot ), SFVEC3F( v1.x, v1.y, layer_z_bot ), SFVEC3F( v1.x, v1.y, layer_z_top ), SFVEC3F( v0.x, v0.y, layer_z_top ) ); const SFVEC2F n0 = glm::normalize( v0 - start ); const SFVEC2F n1 = glm::normalize( v1 - start ); const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f ); const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z ); } } roundedEndPointsStart.clear(); if( roundedEndPointsEnd.size() > 1 ) { for( unsigned int i = 0; i < ( roundedEndPointsEnd.size() - 1 ); ++i ) { const SFVEC2F &v0 = roundedEndPointsEnd[i + 0]; const SFVEC2F &v1 = roundedEndPointsEnd[i + 1]; layerTriangles->m_layer_middle_contourns_quads->AddQuad( SFVEC3F( v0.x, v0.y, layer_z_top ), SFVEC3F( v1.x, v1.y, layer_z_top ), SFVEC3F( v1.x, v1.y, layer_z_bot ), SFVEC3F( v0.x, v0.y, layer_z_bot ) ); const SFVEC2F n0 = glm::normalize( v0 - end ); const SFVEC2F n1 = glm::normalize( v1 - end ); const SFVEC3F n0z = SFVEC3F( n0.x, n0.y, 0.0f ); const SFVEC3F n1z = SFVEC3F( n1.x, n1.y, 0.0f ); layerTriangles->m_layer_middle_contourns_quads->AddNormal( n0z, n1z, n1z, n0z ); } } roundedEndPointsEnd.clear(); } break; default: { } break; } #if 0 // not yet used / implemented (can be used in future to clip the objects in the board borders COBJECT2D *object2d_C = CSGITEM_FULL; std::vector<const COBJECT2D *> *object2d_B = CSGITEM_EMPTY; if( m_settings.GetFlag( FL_RENDER_SHOW_HOLES_IN_ZONES ) ) { object2d_B = new std::vector<const COBJECT2D *>(); // Check if there are any layerhole that intersects this object // Eg: a segment is cutted by a via hole or THT hole. // ///////////////////////////////////////////////////////////// const MAP_CONTAINER_2D &layerHolesMap = m_settings.GetMapLayersHoles(); if( layerHolesMap.find(layer_id) != layerHolesMap.end() ) { MAP_CONTAINER_2D::const_iterator ii_hole = layerHolesMap.find(layer_id); const CBVHCONTAINER2D *containerLayerHoles2d = static_cast<const CBVHCONTAINER2D *>(ii_hole->second); CONST_LIST_OBJECT2D intersectionList; containerLayerHoles2d->GetListObjectsIntersects( object2d_A->GetBBox(), intersectionList ); if( !intersectionList.empty() ) { for( CONST_LIST_OBJECT2D::const_iterator holeOnLayer = intersectionList.begin(); holeOnLayer != intersectionList.end(); holeOnLayer++ ) { const COBJECT2D *hole2d = static_cast<const COBJECT2D *>(*holeOnLayer); //if( object2d_A->Intersects( hole2d->GetBBox() ) ) //if( object2d_A->GetBBox().Intersects( hole2d->GetBBox() ) ) object2d_B->push_back( hole2d ); } } } // Check if there are any THT that intersects this object // ///////////////////////////////////////////////////////////// if( !m_settings.GetThroughHole_Inflated().GetList().empty() ) { CONST_LIST_OBJECT2D intersectionList; m_settings.GetThroughHole_Inflated().GetListObjectsIntersects( object2d_A->GetBBox(), intersectionList ); if( !intersectionList.empty() ) { for( CONST_LIST_OBJECT2D::const_iterator hole = intersectionList.begin(); hole != intersectionList.end(); hole++ ) { const COBJECT2D *hole2d = static_cast<const COBJECT2D *>(*hole); //if( object2d_A->Intersects( hole2d->GetBBox() ) ) //if( object2d_A->GetBBox().Intersects( hole2d->GetBBox() ) ) object2d_B->push_back( hole2d ); } } } if( object2d_B->empty() ) { delete object2d_B; object2d_B = CSGITEM_EMPTY; } } if( (object2d_B == CSGITEM_EMPTY) && (object2d_C == CSGITEM_FULL) ) { #if 0 create_3d_object_from( m_object_container, object2d_A, m_settings.GetLayerBottomZpos3DU( layer_id ), m_settings.GetLayerTopZpos3DU( layer_id ), materialLayer, layerColor ); #else CLAYERITEM *objPtr = new CLAYERITEM( object2d_A, m_settings.GetLayerBottomZpos3DU( layer_id ), m_settings.GetLayerTopZpos3DU( layer_id ) ); objPtr->SetMaterial( materialLayer ); objPtr->SetColor( layerColor ); m_object_container.Add( objPtr ); #endif } else { #if 1 CITEMLAYERCSG2D *itemCSG2d = new CITEMLAYERCSG2D( object2d_A, object2d_B, object2d_C, object2d_A->GetBoardItem() ); m_containerWithObjectsToDelete.Add( itemCSG2d ); CLAYERITEM *objPtr = new CLAYERITEM( itemCSG2d, m_settings.GetLayerBottomZpos3DU( layer_id ), m_settings.GetLayerTopZpos3DU( layer_id ) ); objPtr->SetMaterial( materialLayer ); objPtr->SetColor( layerColor ); m_object_container.Add( objPtr ); #endif } #endif } // Create display list // ///////////////////////////////////////////////////////////////////// m_ogl_disp_lists_layers[layer_id] = new CLAYERS_OGL_DISP_LISTS( *layerTriangles, m_ogl_circle_texture, layerColor ); }// for each layer on map }
/* Plot outlines of copper, for copper layer */ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask, const PCB_PLOT_PARAMS& aPlotOpt ) { BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt ); itemplotter.SetLayerSet( aLayerMask ); SHAPE_POLY_SET outlines; for( LSEQ seq = aLayerMask.Seq( plot_seq, DIM( plot_seq ) ); seq; ++seq ) { LAYER_ID layer = *seq; outlines.RemoveAllContours(); aBoard->ConvertBrdLayerToPolygonalContours( layer, outlines ); outlines.Simplify(); // Plot outlines std::vector< wxPoint > cornerList; // Now we have one or more basic polygons: plot each polygon for( int ii = 0; ii < outlines.OutlineCount(); ii++ ) { for(int kk = 0; kk <= outlines.HoleCount (ii); kk++ ) { cornerList.clear(); const SHAPE_LINE_CHAIN& path = (kk == 0) ? outlines.COutline( ii ) : outlines.CHole( ii, kk - 1 ); for( int jj = 0; jj < path.PointCount(); jj++ ) cornerList.push_back( wxPoint( path.CPoint( jj ).x , path.CPoint( jj ).y ) ); // Ensure the polygon is closed if( cornerList[0] != cornerList[cornerList.size() - 1] ) cornerList.push_back( cornerList[0] ); aPlotter->PlotPoly( cornerList, NO_FILL ); } } // Plot pad holes if( aPlotOpt.GetDrillMarksType() != PCB_PLOT_PARAMS::NO_DRILL_SHAPE ) { for( MODULE* module = aBoard->m_Modules; module; module = module->Next() ) { for( D_PAD* pad = module->Pads(); pad; pad = pad->Next() ) { wxSize hole = pad->GetDrillSize(); if( hole.x == 0 || hole.y == 0 ) continue; if( hole.x == hole.y ) aPlotter->Circle( pad->GetPosition(), hole.x, NO_FILL ); else { wxPoint drl_start, drl_end; int width; pad->GetOblongDrillGeometry( drl_start, drl_end, width ); aPlotter->ThickSegment( pad->GetPosition() + drl_start, pad->GetPosition() + drl_end, width, SKETCH ); } } } } // Plot vias holes for( TRACK* track = aBoard->m_Track; track; track = track->Next() ) { const VIA* via = dyn_cast<const VIA*>( track ); if( via && via->IsOnLayer( layer ) ) // via holes can be not through holes { aPlotter->Circle( via->GetPosition(), via->GetDrillValue(), NO_FILL ); } } } }