feat(webgl): Add 4 new GAL test scenarios for expanded coverage
Expand test coverage from ~19% to ~25% of GAL API with modular scenario files: - bezier-curves: Tests DrawCurve() with S-curves, waves, hearts, and control points - arc-segments: Tests DrawArcSegment() with thick arc strokes (PCB trace style) - segment-chain: Tests DrawSegmentChain() with zigzags, spirals, sharp corners - group-caching: Tests BeginGroup/EndGroup/DrawGroup for cached geometry Architecture: - New scenarios in separate files under scenarios/ - Forward declarations in main gal_test_scenarios.cpp - CMakeLists.txt updated to compile new scenario modules Also: - Remove unused build-wxwidgets-native.sh (using system wxWidgets) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
490f531521
commit
650109e10f
11 changed files with 669 additions and 64 deletions
|
|
@ -1,62 +0,0 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Build wxWidgets for native macOS (not WASM)
|
||||
# This is used for the native GAL test harness
|
||||
#
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
WX_SRC="$PROJECT_ROOT/wxwidgets"
|
||||
BUILD_DIR="$PROJECT_ROOT/build-native/wxwidgets"
|
||||
INSTALL_DIR="$PROJECT_ROOT/build-native/wxwidgets-install"
|
||||
LOG_FILE="$PROJECT_ROOT/tests/logs/wxwidgets-native-build.log"
|
||||
|
||||
mkdir -p "$(dirname "$LOG_FILE")"
|
||||
|
||||
echo "Building wxWidgets for native macOS..."
|
||||
echo " Source: $WX_SRC"
|
||||
echo " Build: $BUILD_DIR"
|
||||
echo " Install: $INSTALL_DIR"
|
||||
echo " Log: $LOG_FILE"
|
||||
|
||||
# Create build directory
|
||||
mkdir -p "$BUILD_DIR"
|
||||
cd "$BUILD_DIR"
|
||||
|
||||
# Set up paths for homebrew libraries
|
||||
export PKG_CONFIG_PATH="/opt/homebrew/lib/pkgconfig:/opt/homebrew/opt/libpng/lib/pkgconfig:$PKG_CONFIG_PATH"
|
||||
export CPPFLAGS="-I/opt/homebrew/include $CPPFLAGS"
|
||||
export LDFLAGS="-L/opt/homebrew/lib $LDFLAGS"
|
||||
|
||||
# Configure wxWidgets for native macOS with OpenGL support
|
||||
echo "Configuring..."
|
||||
"$WX_SRC/configure" \
|
||||
--prefix="$INSTALL_DIR" \
|
||||
--disable-shared \
|
||||
--with-opengl \
|
||||
--with-osx_cocoa \
|
||||
--disable-webview \
|
||||
--disable-mediactrl \
|
||||
--with-libpng=sys \
|
||||
--with-libjpeg=sys \
|
||||
--with-libtiff=sys \
|
||||
--with-zlib=sys \
|
||||
>> "$LOG_FILE" 2>&1
|
||||
|
||||
# Build
|
||||
echo "Building (this may take a while)..."
|
||||
make -j$(sysctl -n hw.ncpu 2>/dev/null || echo 4) >> "$LOG_FILE" 2>&1
|
||||
|
||||
# Install
|
||||
echo "Installing..."
|
||||
make install >> "$LOG_FILE" 2>&1
|
||||
|
||||
echo ""
|
||||
echo "wxWidgets native build complete!"
|
||||
echo "wx-config: $INSTALL_DIR/bin/wx-config"
|
||||
echo ""
|
||||
echo "To use in CMake:"
|
||||
echo " set(wxWidgets_CONFIG_EXECUTABLE $INSTALL_DIR/bin/wx-config)"
|
||||
echo " find_package(wxWidgets REQUIRED COMPONENTS core base gl)"
|
||||
BIN
tests/gal-regression/baseline/gal-arc-segments.png
Normal file
BIN
tests/gal-regression/baseline/gal-arc-segments.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 93 KiB |
BIN
tests/gal-regression/baseline/gal-bezier-curves.png
Normal file
BIN
tests/gal-regression/baseline/gal-bezier-curves.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
BIN
tests/gal-regression/baseline/gal-group-caching.png
Normal file
BIN
tests/gal-regression/baseline/gal-group-caching.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 76 KiB |
BIN
tests/gal-regression/baseline/gal-segment-chain.png
Normal file
BIN
tests/gal-regression/baseline/gal-segment-chain.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
|
|
@ -62,13 +62,23 @@ set(KICAD_GAL_SOURCES
|
|||
set(STUB_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/kicad_stubs.cpp
|
||||
${CMAKE_SOURCE_DIR}/gal_test_accessor.cpp
|
||||
)
|
||||
|
||||
# Test scenario files
|
||||
set(SCENARIO_SOURCES
|
||||
${CMAKE_SOURCE_DIR}/../scenarios/gal_test_scenarios.cpp
|
||||
# New modular scenarios
|
||||
${CMAKE_SOURCE_DIR}/../scenarios/scenario_bezier_curves.cpp
|
||||
${CMAKE_SOURCE_DIR}/../scenarios/scenario_arc_segments.cpp
|
||||
${CMAKE_SOURCE_DIR}/../scenarios/scenario_segment_chain.cpp
|
||||
${CMAKE_SOURCE_DIR}/../scenarios/scenario_group_caching.cpp
|
||||
)
|
||||
|
||||
# Main executable
|
||||
add_executable(gal_native_test
|
||||
gal_native_test.cpp
|
||||
${STUB_SOURCES}
|
||||
${SCENARIO_SOURCES}
|
||||
${KICAD_GAL_SOURCES}
|
||||
${SHADER_SOURCES}
|
||||
)
|
||||
|
|
|
|||
|
|
@ -3,6 +3,13 @@
|
|||
*
|
||||
* Uses KiCad's GAL API to render test patterns.
|
||||
* These serve as baselines for WEBGL_GAL visual regression testing.
|
||||
*
|
||||
* This file contains the original 11 scenarios (0-10).
|
||||
* Additional scenarios are in separate files:
|
||||
* - scenario_bezier_curves.cpp (11)
|
||||
* - scenario_arc_segments.cpp (12)
|
||||
* - scenario_segment_chain.cpp (13)
|
||||
* - scenario_group_caching.cpp (14)
|
||||
*/
|
||||
|
||||
#include "gal_test_scenarios.h"
|
||||
|
|
@ -25,8 +32,15 @@ namespace GALTest {
|
|||
using KIGFX::COLOR4D;
|
||||
using KIGFX::GAL;
|
||||
|
||||
// Scenario names
|
||||
// Forward declarations for scenarios in separate files
|
||||
void RenderBezierCurves(GAL* gal, int width, int height);
|
||||
void RenderArcSegments(GAL* gal, int width, int height);
|
||||
void RenderSegmentChain(GAL* gal, int width, int height);
|
||||
void RenderGroupCaching(GAL* gal, int width, int height);
|
||||
|
||||
// Scenario names - original 11 + 4 new scenarios
|
||||
static const char* SCENARIO_NAMES[] = {
|
||||
// Original scenarios (0-10)
|
||||
"basic-lines",
|
||||
"line-widths",
|
||||
"circles",
|
||||
|
|
@ -37,7 +51,12 @@ static const char* SCENARIO_NAMES[] = {
|
|||
"transforms",
|
||||
"grid-cursor",
|
||||
"segments",
|
||||
"complex-scene"
|
||||
"complex-scene",
|
||||
// New scenarios (11-14) - defined in separate files
|
||||
"bezier-curves",
|
||||
"arc-segments",
|
||||
"segment-chain",
|
||||
"group-caching"
|
||||
};
|
||||
|
||||
static const int SCENARIO_COUNT = sizeof(SCENARIO_NAMES) / sizeof(SCENARIO_NAMES[0]);
|
||||
|
|
@ -549,6 +568,7 @@ static void RenderComplexScene(KIGFX::GAL* gal, int width, int height) {
|
|||
|
||||
void RenderScenario(KIGFX::GAL* gal, int index, int width, int height) {
|
||||
switch (index) {
|
||||
// Original scenarios (0-10) - defined in this file
|
||||
case 0: RenderBasicLines(gal, width, height); break;
|
||||
case 1: RenderLineWidths(gal, width, height); break;
|
||||
case 2: RenderCircles(gal, width, height); break;
|
||||
|
|
@ -560,6 +580,11 @@ void RenderScenario(KIGFX::GAL* gal, int index, int width, int height) {
|
|||
case 8: RenderGridCursor(gal, width, height); break;
|
||||
case 9: RenderSegments(gal, width, height); break;
|
||||
case 10: RenderComplexScene(gal, width, height); break;
|
||||
// New scenarios (11-14) - defined in separate files
|
||||
case 11: RenderBezierCurves(gal, width, height); break;
|
||||
case 12: RenderArcSegments(gal, width, height); break;
|
||||
case 13: RenderSegmentChain(gal, width, height); break;
|
||||
case 14: RenderGroupCaching(gal, width, height); break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
161
tests/gal-regression/scenarios/scenario_arc_segments.cpp
Normal file
161
tests/gal-regression/scenarios/scenario_arc_segments.cpp
Normal file
|
|
@ -0,0 +1,161 @@
|
|||
/**
|
||||
* Arc Segments Scenario
|
||||
*
|
||||
* Tests GAL::DrawArcSegment() - thick arc strokes
|
||||
*
|
||||
* Unlike DrawArc() which draws pie slices when filled,
|
||||
* DrawArcSegment() draws thick arc strokes (like a PCB trace).
|
||||
*/
|
||||
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <geometry/eda_angle.h>
|
||||
#include <cmath>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
namespace GALTest {
|
||||
|
||||
using KIGFX::COLOR4D;
|
||||
using KIGFX::GAL;
|
||||
|
||||
void RenderArcSegments(GAL* gal, int width, int height) {
|
||||
double cx = width / 2.0;
|
||||
double cy = height / 2.0;
|
||||
double maxError = 0.01; // Segment approximation error
|
||||
|
||||
// Thick arc segments with varying widths
|
||||
gal->SetIsFill(true);
|
||||
gal->SetIsStroke(false);
|
||||
|
||||
// 90-degree arcs at different widths
|
||||
double widths[] = {5.0, 10.0, 20.0, 30.0};
|
||||
double radius = 80;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
double t = (double)i / 3.0;
|
||||
gal->SetFillColor(COLOR4D(1.0 - t * 0.5, 0.3 + t * 0.4, 0.2 + t * 0.6, 1.0));
|
||||
|
||||
EDA_ANGLE startAngle(i * 90, DEGREES_T);
|
||||
EDA_ANGLE arcAngle(90, DEGREES_T);
|
||||
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx - 200, cy - 100),
|
||||
radius,
|
||||
startAngle,
|
||||
arcAngle,
|
||||
widths[i],
|
||||
maxError
|
||||
);
|
||||
}
|
||||
|
||||
// Full ring using arc segments
|
||||
gal->SetFillColor(COLOR4D(0.8, 0.6, 0.2, 1.0));
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx, cy - 100),
|
||||
60,
|
||||
EDA_ANGLE(0, DEGREES_T),
|
||||
EDA_ANGLE(360, DEGREES_T),
|
||||
15,
|
||||
maxError
|
||||
);
|
||||
|
||||
// Half rings
|
||||
gal->SetFillColor(COLOR4D(0.2, 0.8, 0.4, 1.0));
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx + 180, cy - 100),
|
||||
70,
|
||||
EDA_ANGLE(0, DEGREES_T),
|
||||
EDA_ANGLE(180, DEGREES_T),
|
||||
12,
|
||||
maxError
|
||||
);
|
||||
|
||||
gal->SetFillColor(COLOR4D(0.4, 0.2, 0.8, 1.0));
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx + 180, cy - 100),
|
||||
70,
|
||||
EDA_ANGLE(180, DEGREES_T),
|
||||
EDA_ANGLE(180, DEGREES_T),
|
||||
8,
|
||||
maxError
|
||||
);
|
||||
|
||||
// Concentric arc segments (like a spiral)
|
||||
double baseRadius = 40;
|
||||
for (int i = 0; i < 5; i++) {
|
||||
double t = (double)i / 4.0;
|
||||
gal->SetFillColor(COLOR4D(t, 0.5, 1.0 - t, 0.9));
|
||||
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx - 150, cy + 150),
|
||||
baseRadius + i * 25,
|
||||
EDA_ANGLE(i * 30, DEGREES_T),
|
||||
EDA_ANGLE(270, DEGREES_T),
|
||||
6,
|
||||
maxError
|
||||
);
|
||||
}
|
||||
|
||||
// Thin arc segments (like copper traces)
|
||||
gal->SetFillColor(COLOR4D(0.9, 0.7, 0.3, 1.0));
|
||||
for (int i = 0; i < 8; i++) {
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx + 100, cy + 150),
|
||||
30 + i * 15,
|
||||
EDA_ANGLE(45, DEGREES_T),
|
||||
EDA_ANGLE(90, DEGREES_T),
|
||||
3,
|
||||
maxError
|
||||
);
|
||||
}
|
||||
|
||||
// Small angle arc segments
|
||||
gal->SetFillColor(COLOR4D(1.0, 0.4, 0.4, 1.0));
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx, cy + 100),
|
||||
100,
|
||||
EDA_ANGLE(0, DEGREES_T),
|
||||
EDA_ANGLE(30, DEGREES_T),
|
||||
20,
|
||||
maxError
|
||||
);
|
||||
|
||||
gal->SetFillColor(COLOR4D(0.4, 1.0, 0.4, 1.0));
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx, cy + 100),
|
||||
100,
|
||||
EDA_ANGLE(60, DEGREES_T),
|
||||
EDA_ANGLE(30, DEGREES_T),
|
||||
20,
|
||||
maxError
|
||||
);
|
||||
|
||||
gal->SetFillColor(COLOR4D(0.4, 0.4, 1.0, 1.0));
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx, cy + 100),
|
||||
100,
|
||||
EDA_ANGLE(120, DEGREES_T),
|
||||
EDA_ANGLE(30, DEGREES_T),
|
||||
20,
|
||||
maxError
|
||||
);
|
||||
|
||||
// Stroked arc segment outline
|
||||
gal->SetIsFill(false);
|
||||
gal->SetIsStroke(true);
|
||||
gal->SetLineWidth(2.0);
|
||||
gal->SetStrokeColor(COLOR4D(1.0, 1.0, 0.0, 1.0));
|
||||
|
||||
gal->DrawArcSegment(
|
||||
VECTOR2D(cx + 200, cy + 100),
|
||||
50,
|
||||
EDA_ANGLE(0, DEGREES_T),
|
||||
EDA_ANGLE(270, DEGREES_T),
|
||||
25,
|
||||
maxError
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace GALTest
|
||||
138
tests/gal-regression/scenarios/scenario_bezier_curves.cpp
Normal file
138
tests/gal-regression/scenarios/scenario_bezier_curves.cpp
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/**
|
||||
* Bezier Curves Scenario
|
||||
*
|
||||
* Tests GAL::DrawCurve() - cubic bezier splines
|
||||
*/
|
||||
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <cmath>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
namespace GALTest {
|
||||
|
||||
using KIGFX::COLOR4D;
|
||||
using KIGFX::GAL;
|
||||
|
||||
void RenderBezierCurves(GAL* gal, int width, int height) {
|
||||
double cx = width / 2.0;
|
||||
double cy = height / 2.0;
|
||||
|
||||
gal->SetIsFill(false);
|
||||
gal->SetIsStroke(true);
|
||||
|
||||
// Simple S-curve
|
||||
gal->SetStrokeColor(COLOR4D(1.0, 0.3, 0.3, 1.0));
|
||||
gal->SetLineWidth(3.0);
|
||||
gal->DrawCurve(
|
||||
VECTOR2D(100, cy - 100), // start
|
||||
VECTOR2D(200, cy - 200), // control 1
|
||||
VECTOR2D(300, cy), // control 2
|
||||
VECTOR2D(400, cy - 100), // end
|
||||
0.0 // filter value
|
||||
);
|
||||
|
||||
// Inverse S-curve below
|
||||
gal->SetStrokeColor(COLOR4D(0.3, 1.0, 0.3, 1.0));
|
||||
gal->DrawCurve(
|
||||
VECTOR2D(100, cy + 100),
|
||||
VECTOR2D(200, cy + 200),
|
||||
VECTOR2D(300, cy),
|
||||
VECTOR2D(400, cy + 100),
|
||||
0.0
|
||||
);
|
||||
|
||||
// Loop curve (tight control points)
|
||||
gal->SetStrokeColor(COLOR4D(0.3, 0.3, 1.0, 1.0));
|
||||
gal->SetLineWidth(2.0);
|
||||
gal->DrawCurve(
|
||||
VECTOR2D(450, cy - 50),
|
||||
VECTOR2D(550, cy - 150),
|
||||
VECTOR2D(550, cy + 150),
|
||||
VECTOR2D(450, cy + 50),
|
||||
0.0
|
||||
);
|
||||
|
||||
// Straight-ish curve (control points on line)
|
||||
gal->SetStrokeColor(COLOR4D(1.0, 1.0, 0.3, 1.0));
|
||||
gal->DrawCurve(
|
||||
VECTOR2D(500, 80),
|
||||
VECTOR2D(550, 80),
|
||||
VECTOR2D(650, 80),
|
||||
VECTOR2D(700, 80),
|
||||
0.0
|
||||
);
|
||||
|
||||
// Wave pattern using multiple curves
|
||||
gal->SetStrokeColor(COLOR4D(0.8, 0.5, 0.8, 1.0));
|
||||
gal->SetLineWidth(2.5);
|
||||
double waveY = height - 100;
|
||||
double segWidth = 100;
|
||||
double amplitude = 40;
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
double x0 = 100 + i * segWidth;
|
||||
double x1 = x0 + segWidth;
|
||||
double dir = (i % 2 == 0) ? 1.0 : -1.0;
|
||||
|
||||
gal->DrawCurve(
|
||||
VECTOR2D(x0, waveY),
|
||||
VECTOR2D(x0 + segWidth * 0.33, waveY + amplitude * dir),
|
||||
VECTOR2D(x0 + segWidth * 0.66, waveY + amplitude * dir),
|
||||
VECTOR2D(x1, waveY),
|
||||
0.0
|
||||
);
|
||||
}
|
||||
|
||||
// Heart shape using two curves
|
||||
gal->SetStrokeColor(COLOR4D(1.0, 0.2, 0.4, 1.0));
|
||||
gal->SetLineWidth(3.0);
|
||||
double hx = cx + 150;
|
||||
double hy = cy - 50;
|
||||
double hs = 50; // heart scale
|
||||
|
||||
// Left half of heart
|
||||
gal->DrawCurve(
|
||||
VECTOR2D(hx, hy + hs * 0.5), // bottom point
|
||||
VECTOR2D(hx - hs * 1.5, hy - hs), // left control
|
||||
VECTOR2D(hx - hs * 0.5, hy - hs * 1.5), // top control
|
||||
VECTOR2D(hx, hy - hs * 0.3), // top middle
|
||||
0.0
|
||||
);
|
||||
|
||||
// Right half of heart
|
||||
gal->DrawCurve(
|
||||
VECTOR2D(hx, hy - hs * 0.3), // top middle
|
||||
VECTOR2D(hx + hs * 0.5, hy - hs * 1.5), // top control
|
||||
VECTOR2D(hx + hs * 1.5, hy - hs), // right control
|
||||
VECTOR2D(hx, hy + hs * 0.5), // bottom point
|
||||
0.0
|
||||
);
|
||||
|
||||
// Control point visualization (draw handles)
|
||||
gal->SetStrokeColor(COLOR4D(0.5, 0.5, 0.5, 0.5));
|
||||
gal->SetLineWidth(1.0);
|
||||
|
||||
// Show control points for the first curve
|
||||
VECTOR2D p0(100, cy - 100);
|
||||
VECTOR2D c0(200, cy - 200);
|
||||
VECTOR2D c1(300, cy);
|
||||
VECTOR2D p1(400, cy - 100);
|
||||
|
||||
gal->DrawLine(p0, c0);
|
||||
gal->DrawLine(p1, c1);
|
||||
|
||||
// Draw control point markers
|
||||
gal->SetIsFill(true);
|
||||
gal->SetIsStroke(false);
|
||||
gal->SetFillColor(COLOR4D(1.0, 0.5, 0.0, 0.8));
|
||||
gal->DrawCircle(c0, 5);
|
||||
gal->DrawCircle(c1, 5);
|
||||
gal->SetFillColor(COLOR4D(0.0, 0.5, 1.0, 0.8));
|
||||
gal->DrawCircle(p0, 5);
|
||||
gal->DrawCircle(p1, 5);
|
||||
}
|
||||
|
||||
} // namespace GALTest
|
||||
191
tests/gal-regression/scenarios/scenario_group_caching.cpp
Normal file
191
tests/gal-regression/scenarios/scenario_group_caching.cpp
Normal file
|
|
@ -0,0 +1,191 @@
|
|||
/**
|
||||
* Group Caching Scenario
|
||||
*
|
||||
* Tests GAL group/caching methods:
|
||||
* - BeginGroup() / EndGroup() - define cached geometry
|
||||
* - DrawGroup() - render cached geometry
|
||||
* - ChangeGroupColor() - modify group color
|
||||
* - ChangeGroupDepth() - modify group depth
|
||||
*
|
||||
* Groups allow geometry to be cached in GPU memory and redrawn
|
||||
* efficiently, useful for static elements that don't change often.
|
||||
*/
|
||||
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <cmath>
|
||||
#include <deque>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
namespace GALTest {
|
||||
|
||||
using KIGFX::COLOR4D;
|
||||
using KIGFX::GAL;
|
||||
|
||||
void RenderGroupCaching(GAL* gal, int width, int height) {
|
||||
double cx = width / 2.0;
|
||||
double cy = height / 2.0;
|
||||
|
||||
// Create a group with a simple pattern
|
||||
gal->SetIsFill(true);
|
||||
gal->SetIsStroke(false);
|
||||
gal->SetFillColor(COLOR4D(0.8, 0.4, 0.2, 1.0));
|
||||
|
||||
int group1 = gal->BeginGroup();
|
||||
{
|
||||
// Draw a simple component symbol
|
||||
gal->DrawRectangle(VECTOR2D(-30, -20), VECTOR2D(30, 20));
|
||||
gal->SetFillColor(COLOR4D(0.3, 0.3, 0.3, 1.0));
|
||||
gal->DrawCircle(VECTOR2D(-15, 0), 8);
|
||||
gal->DrawCircle(VECTOR2D(15, 0), 8);
|
||||
}
|
||||
gal->EndGroup();
|
||||
|
||||
// Create another group with different geometry
|
||||
gal->SetFillColor(COLOR4D(0.2, 0.6, 0.8, 1.0));
|
||||
|
||||
int group2 = gal->BeginGroup();
|
||||
{
|
||||
// Draw a triangle marker
|
||||
std::deque<VECTOR2D> tri = {
|
||||
VECTOR2D(0, -25),
|
||||
VECTOR2D(-20, 15),
|
||||
VECTOR2D(20, 15)
|
||||
};
|
||||
gal->DrawPolygon(tri);
|
||||
}
|
||||
gal->EndGroup();
|
||||
|
||||
// Create a more complex group
|
||||
gal->SetFillColor(COLOR4D(0.6, 0.2, 0.6, 1.0));
|
||||
gal->SetIsStroke(true);
|
||||
gal->SetIsFill(false);
|
||||
gal->SetLineWidth(2.0);
|
||||
gal->SetStrokeColor(COLOR4D(0.8, 0.8, 0.2, 1.0));
|
||||
|
||||
int group3 = gal->BeginGroup();
|
||||
{
|
||||
// Draw a star outline
|
||||
for (int i = 0; i < 5; i++) {
|
||||
double angle1 = -M_PI / 2 + i * 2 * M_PI / 5;
|
||||
double angle2 = -M_PI / 2 + ((i + 2) % 5) * 2 * M_PI / 5;
|
||||
gal->DrawLine(
|
||||
VECTOR2D(cos(angle1) * 30, sin(angle1) * 30),
|
||||
VECTOR2D(cos(angle2) * 30, sin(angle2) * 30)
|
||||
);
|
||||
}
|
||||
}
|
||||
gal->EndGroup();
|
||||
|
||||
// Now draw the groups at different positions
|
||||
|
||||
// Draw group1 multiple times
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(100, 100));
|
||||
gal->DrawGroup(group1);
|
||||
gal->Restore();
|
||||
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(250, 100));
|
||||
gal->DrawGroup(group1);
|
||||
gal->Restore();
|
||||
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(400, 100));
|
||||
gal->Rotate(45.0 * M_PI / 180.0);
|
||||
gal->DrawGroup(group1);
|
||||
gal->Restore();
|
||||
|
||||
// Draw group2 multiple times
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(100, 250));
|
||||
gal->DrawGroup(group2);
|
||||
gal->Restore();
|
||||
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(200, 250));
|
||||
gal->Scale(VECTOR2D(1.5, 1.5));
|
||||
gal->DrawGroup(group2);
|
||||
gal->Restore();
|
||||
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(320, 250));
|
||||
gal->Rotate(180.0 * M_PI / 180.0);
|
||||
gal->DrawGroup(group2);
|
||||
gal->Restore();
|
||||
|
||||
// Draw group3 multiple times
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(500, 200));
|
||||
gal->DrawGroup(group3);
|
||||
gal->Restore();
|
||||
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(600, 200));
|
||||
gal->Scale(VECTOR2D(1.3, 1.3));
|
||||
gal->DrawGroup(group3);
|
||||
gal->Restore();
|
||||
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(700, 200));
|
||||
gal->Rotate(36.0 * M_PI / 180.0);
|
||||
gal->DrawGroup(group3);
|
||||
gal->Restore();
|
||||
|
||||
// Test ChangeGroupColor - redraw with different colors
|
||||
gal->ChangeGroupColor(group1, COLOR4D(0.2, 0.8, 0.4, 1.0));
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(100, 400));
|
||||
gal->DrawGroup(group1);
|
||||
gal->Restore();
|
||||
|
||||
gal->ChangeGroupColor(group1, COLOR4D(0.4, 0.4, 0.9, 1.0));
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(250, 400));
|
||||
gal->DrawGroup(group1);
|
||||
gal->Restore();
|
||||
|
||||
// Test ChangeGroupDepth
|
||||
gal->SetLayerDepth(50);
|
||||
gal->ChangeGroupDepth(group2, 30);
|
||||
gal->Save();
|
||||
gal->Translate(VECTOR2D(450, 400));
|
||||
gal->DrawGroup(group2);
|
||||
gal->Restore();
|
||||
|
||||
// Draw a rectangle to show depth ordering
|
||||
gal->SetLayerDepth(40);
|
||||
gal->SetIsFill(true);
|
||||
gal->SetIsStroke(false);
|
||||
gal->SetFillColor(COLOR4D(1.0, 0.5, 0.5, 0.7));
|
||||
gal->DrawRectangle(VECTOR2D(430, 385), VECTOR2D(470, 430));
|
||||
|
||||
// Labels using simple geometry (no text)
|
||||
gal->SetLayerDepth(10);
|
||||
gal->SetIsFill(false);
|
||||
gal->SetIsStroke(true);
|
||||
gal->SetLineWidth(1.0);
|
||||
gal->SetStrokeColor(COLOR4D(0.5, 0.5, 0.5, 1.0));
|
||||
|
||||
// "Group 1" marker
|
||||
gal->DrawRectangle(VECTOR2D(80, 60), VECTOR2D(180, 75));
|
||||
|
||||
// "Group 2" marker
|
||||
gal->DrawRectangle(VECTOR2D(80, 210), VECTOR2D(180, 225));
|
||||
|
||||
// "Group 3" marker
|
||||
gal->DrawRectangle(VECTOR2D(480, 160), VECTOR2D(580, 175));
|
||||
|
||||
// Grid pattern to show group reuse efficiency
|
||||
gal->SetStrokeColor(COLOR4D(0.3, 0.3, 0.3, 0.3));
|
||||
for (int x = 0; x < width; x += 50) {
|
||||
gal->DrawLine(VECTOR2D(x, 0), VECTOR2D(x, height));
|
||||
}
|
||||
for (int y = 0; y < height; y += 50) {
|
||||
gal->DrawLine(VECTOR2D(0, y), VECTOR2D(width, y));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GALTest
|
||||
142
tests/gal-regression/scenarios/scenario_segment_chain.cpp
Normal file
142
tests/gal-regression/scenarios/scenario_segment_chain.cpp
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
/**
|
||||
* Segment Chain Scenario
|
||||
*
|
||||
* Tests GAL::DrawSegmentChain() - connected thick segments with round joins
|
||||
*
|
||||
* This is used for drawing thick polylines like PCB traces with proper
|
||||
* join handling between segments.
|
||||
*/
|
||||
|
||||
#include <gal/graphics_abstraction_layer.h>
|
||||
#include <cmath>
|
||||
#include <vector>
|
||||
|
||||
#ifndef M_PI
|
||||
#define M_PI 3.14159265358979323846
|
||||
#endif
|
||||
|
||||
namespace GALTest {
|
||||
|
||||
using KIGFX::COLOR4D;
|
||||
using KIGFX::GAL;
|
||||
|
||||
void RenderSegmentChain(GAL* gal, int width, int height) {
|
||||
double cx = width / 2.0;
|
||||
double cy = height / 2.0;
|
||||
|
||||
gal->SetIsFill(true);
|
||||
gal->SetIsStroke(false);
|
||||
|
||||
// Simple zigzag chain
|
||||
gal->SetFillColor(COLOR4D(0.9, 0.6, 0.2, 1.0));
|
||||
std::vector<VECTOR2D> zigzag = {
|
||||
VECTOR2D(80, 80),
|
||||
VECTOR2D(180, 150),
|
||||
VECTOR2D(280, 80),
|
||||
VECTOR2D(380, 150),
|
||||
VECTOR2D(480, 80)
|
||||
};
|
||||
gal->DrawSegmentChain(zigzag, 12.0);
|
||||
|
||||
// Smooth wave chain
|
||||
gal->SetFillColor(COLOR4D(0.2, 0.7, 0.9, 1.0));
|
||||
std::vector<VECTOR2D> wave;
|
||||
for (int i = 0; i <= 20; i++) {
|
||||
double t = (double)i / 20.0;
|
||||
double x = 80 + t * 400;
|
||||
double y = 220 + sin(t * M_PI * 3) * 40;
|
||||
wave.push_back(VECTOR2D(x, y));
|
||||
}
|
||||
gal->DrawSegmentChain(wave, 8.0);
|
||||
|
||||
// Sharp corners (tests join handling)
|
||||
gal->SetFillColor(COLOR4D(0.8, 0.3, 0.5, 1.0));
|
||||
std::vector<VECTOR2D> sharp = {
|
||||
VECTOR2D(550, 80),
|
||||
VECTOR2D(650, 80),
|
||||
VECTOR2D(650, 180),
|
||||
VECTOR2D(550, 180),
|
||||
VECTOR2D(550, 130),
|
||||
VECTOR2D(700, 130)
|
||||
};
|
||||
gal->DrawSegmentChain(sharp, 10.0);
|
||||
|
||||
// Spiral chain
|
||||
gal->SetFillColor(COLOR4D(0.5, 0.8, 0.3, 1.0));
|
||||
std::vector<VECTOR2D> spiral;
|
||||
double spiralCx = cx - 150;
|
||||
double spiralCy = cy + 100;
|
||||
for (int i = 0; i <= 30; i++) {
|
||||
double angle = i * M_PI / 6;
|
||||
double radius = 20 + i * 3;
|
||||
spiral.push_back(VECTOR2D(
|
||||
spiralCx + cos(angle) * radius,
|
||||
spiralCy + sin(angle) * radius
|
||||
));
|
||||
}
|
||||
gal->DrawSegmentChain(spiral, 6.0);
|
||||
|
||||
// Varying width segments (multiple chains)
|
||||
double widths[] = {3.0, 6.0, 10.0, 15.0, 20.0};
|
||||
for (int w = 0; w < 5; w++) {
|
||||
double t = (double)w / 4.0;
|
||||
gal->SetFillColor(COLOR4D(1.0 - t * 0.5, 0.3 + t * 0.4, 0.3 + t * 0.5, 1.0));
|
||||
|
||||
std::vector<VECTOR2D> line = {
|
||||
VECTOR2D(80, 320 + w * 45),
|
||||
VECTOR2D(200, 340 + w * 45),
|
||||
VECTOR2D(280, 310 + w * 45)
|
||||
};
|
||||
gal->DrawSegmentChain(line, widths[w]);
|
||||
}
|
||||
|
||||
// Acute angle chain (stress test for joins)
|
||||
gal->SetFillColor(COLOR4D(1.0, 0.5, 0.2, 1.0));
|
||||
std::vector<VECTOR2D> acute = {
|
||||
VECTOR2D(400, 350),
|
||||
VECTOR2D(500, 350),
|
||||
VECTOR2D(420, 380), // Very acute angle back
|
||||
VECTOR2D(520, 380),
|
||||
VECTOR2D(440, 410),
|
||||
VECTOR2D(540, 410)
|
||||
};
|
||||
gal->DrawSegmentChain(acute, 8.0);
|
||||
|
||||
// Star pattern chain
|
||||
gal->SetFillColor(COLOR4D(0.9, 0.9, 0.2, 1.0));
|
||||
std::vector<VECTOR2D> star;
|
||||
double starCx = cx + 180;
|
||||
double starCy = cy + 120;
|
||||
double outerR = 60;
|
||||
double innerR = 25;
|
||||
for (int i = 0; i <= 10; i++) {
|
||||
double angle = i * M_PI / 5 - M_PI / 2;
|
||||
double r = (i % 2 == 0) ? outerR : innerR;
|
||||
star.push_back(VECTOR2D(
|
||||
starCx + cos(angle) * r,
|
||||
starCy + sin(angle) * r
|
||||
));
|
||||
}
|
||||
gal->DrawSegmentChain(star, 5.0);
|
||||
|
||||
// Single segment (degenerate case)
|
||||
gal->SetFillColor(COLOR4D(0.6, 0.4, 0.8, 1.0));
|
||||
std::vector<VECTOR2D> single = {
|
||||
VECTOR2D(600, 280),
|
||||
VECTOR2D(720, 320)
|
||||
};
|
||||
gal->DrawSegmentChain(single, 15.0);
|
||||
|
||||
// Very thin chain
|
||||
gal->SetFillColor(COLOR4D(0.3, 0.3, 0.3, 1.0));
|
||||
std::vector<VECTOR2D> thin;
|
||||
for (int i = 0; i <= 15; i++) {
|
||||
double t = (double)i / 15.0;
|
||||
double x = 550 + t * 180;
|
||||
double y = 450 + sin(t * M_PI * 4) * 20;
|
||||
thin.push_back(VECTOR2D(x, y));
|
||||
}
|
||||
gal->DrawSegmentChain(thin, 2.0);
|
||||
}
|
||||
|
||||
} // namespace GALTest
|
||||
Loading…
Reference in a new issue