📄 ps.cpp
字号:
{ byte *Warnings = (byte *)calloc(Shape.nrows(), 1); // Warnings just to help layout in PsAnnotatedShape CheckShape(Warnings, false, Shape, s); PsAnnotatedShape(Shape, Warnings, sPsFile, pPsFile, PsScale, Color, 0, s); free(Warnings); }else PsShape(Shape, pPsFile, PsScale, Color, 0, s);PsPageTitle(pPsFile, s);if (fFooter) PsPageFooter(pPsFile);}//-----------------------------------------------------------------------------// Draw a shape with the orthogonal "whiskers" at the points. A whisker is// a line perpendicular to the point wrt the points on each side of it. It is// used for profile statistics in pattern matching.void PsShapeWithWhiskers (const SHAPE &Shape, bool fAnnotate, // in const byte Warnings[], int nSamplePoints, // in const char *sFile, FILE *pFile, double Scale, unsigned Color, double Width, // in double ProfAngle, const tLand Lands[], const SHAPE &AlignedAvShape, // in const char *sMsg, int i, int j) // in{if (fAnnotate) PsAnnotatedShape(Shape, Warnings, sFile, pFile, Scale, Color, Width, sMsg, i, j);else PsShape(Shape, pFile, Scale, Color, Width, sMsg, i, j);Fprintf(pFile, "%% Whiskers\n");PsColor(pFile, Color);for (int iPoint = 0; iPoint < Shape.nrows(); iPoint++) { if (!fPointUsed(Shape, iPoint)) continue; double DeltaX, DeltaY; GetProfStepSize(&DeltaX, &DeltaY, Shape, iPoint, ProfAngle, Lands, AlignedAvShape); double ScaledDeltaX = Scale * DeltaX, ScaledDeltaY = Scale * DeltaY; Fprintf(pFile, "%.4g %.4g moveto %.4g %.4g rlineto stroke\n", // draw whisker Scale * GetX(Shape(iPoint, VX), -nSamplePoints, 0, DeltaX, DeltaY), Scale * GetY(Shape(iPoint, VY), -nSamplePoints, 0, DeltaX, DeltaY), 2 * nSamplePoints * ScaledDeltaX, 2 * nSamplePoints * ScaledDeltaY); double x = Scale * GetX(Shape(iPoint, VX), -nSamplePoints, 0, DeltaX, DeltaY); // big circle around 1st point double y = Scale * GetY(Shape(iPoint, VY), -nSamplePoints, 0, DeltaX, DeltaY); Fprintf(pFile, "%.4g %.4g %.4g 0 360 arc stroke\n", x, y, 2.0); for (int iSample = -nSamplePoints; iSample <= nSamplePoints; iSample++) // small dots on all points { x = Scale * GetX(Shape(iPoint, VX), iSample, 0, DeltaX, DeltaY); y = Scale * GetY(Shape(iPoint, VY), iSample, 0, DeltaX, DeltaY); Fprintf(pFile, "%.4g %.4g %.4g 0 360 arc stroke\n", x, y, 0.2); } }}//-----------------------------------------------------------------------------// Make a postscript page displaying all the shapes in aShapesvoid PsShapes (int *pnPage, // io char sPageTitle[], char sShapeLabel[], // in const SHAPE *aShapes, int nShapes, // in const char *sFile, FILE *pFile, // in unsigned Color, double Width) // in{PsPageHeader(pFile, (*pnPage)++);double PsScale = EstPsScale(aShapes, nShapes, 1.5);PsPageTitle(pFile, sPageTitle);for (int iShape = 0; iShape < nShapes; iShape++) PsShape(aShapes[iShape], pFile, PsScale, Color, Width, "Initial shape %d", iShape);PsShapeLabel(aShapes[0], pFile, PsScale, sShapeLabel);PsPageFooter(pFile);}//-----------------------------------------------------------------------------// Shapes and images we be overlaid correctly on top of each other, provided// Scale is the same i.e. we scale things so one pixel equals one postscript unitvoid PsImage (const Image &Img, double Scale, FILE *pFile, const char *sMsg){Fprintf(pFile, "%% Image %s\n", sMsg);byte Gray = !Img(0); // "!" forces first pixel to be drawnint width = Img.width, height = Img.height;int Resolution = gPsImageResolution;#if 1if (width >= 400) Resolution = 2; // can't wait all day for those postscript images to be displayed#endifif (width < 300 || Resolution > 1) { Fprintf(pFile, "/graypixel { moveto setgray 1 1 rlineto 0 -1 rlineto -1 -1 rlineto stroke } def\n"); Fprintf(pFile, "/pixel { moveto 1 1 rlineto 0 -1 rlineto -1 -1 rlineto stroke } def\n"); }else { Fprintf(pFile, "/graypixel { moveto setgray 1 1 rlineto stroke } def\n"); Fprintf(pFile, "/pixel { moveto 1 1 rlineto stroke } def\n"); }Fprintf(pFile, "gsave %d setlinewidth\n", int(1000 / width + 1));for (int iy = height/2-1; iy >= -height/2; iy -= Resolution) for (int ix = -width/2; ix < width/2; ix += Resolution) { byte Pixel = iGetPixel(Img, ix, iy); if (Pixel <= gPsMaxGray && Pixel >= gPsMinGray) if (Pixel != Gray) { Gray = Pixel; Fprintf(pFile, "%.4g %.4g %.4g graypixel\n", (double)Gray / 255, ix * Scale - 0.5, iy * Scale - 0.5); } else Fprintf(pFile, "%.4g %.4g pixel\n", ix * Scale - 0.5, iy * Scale - 0.5); }Fprintf(pFile, "grestore\n");}//-----------------------------------------------------------------------------// like DisplayImage but displays RGB imagesvoid PsRgbImage (const RgbImage &Img, double Scale, FILE *pFile, const char *sMsg){Fprintf(pFile, "%% Image %s\n", sMsg); // two %% will actually print one %tRGB Pixel = Img(0);byte Red = !Pixel.Red, Green = 0, Blue = 0;int width = Img.width, height = Img.height;int Resolution = gPsImageResolution;#if 1if (width >= 400) Resolution = 3; // can't wait all day for thos postscript images to be displayed!#endifif (width < 300 || Resolution > 1) { Fprintf(pFile, "/colorpixel { moveto setrgbcolor 1 1 rlineto 0 -1 rlineto -1 -1 rlineto stroke } def\n"); Fprintf(pFile, "/pixel { moveto 1 1 rlineto 0 -1 rlineto -1 -1 rlineto stroke } def\n"); }else { Fprintf(pFile, "/colorpixel { moveto setrgbcolor 1 1 rlineto stroke } def\n"); Fprintf(pFile, "/pixel { moveto 1 1 rlineto stroke } def\n"); }Fprintf(pFile, "gsave %d setlinewidth\n", int(1000 / width + 1));for (int iy = height/2-1; iy >= -height/2; iy -= Resolution) for (int ix = -width/2; ix < width/2; ix += Resolution) { tRGB Pixel = Img.pixel(ix, iy); if (Pixel.Red <= gPsMaxGray && Pixel.Green <= gPsMaxGray && Pixel.Blue <= gPsMaxGray && Pixel.Red >= gPsMinGray && Pixel.Green >= gPsMinGray && Pixel.Blue >= gPsMinGray) { if (Pixel.Red != Red || Pixel.Green != Green || Pixel.Blue != Blue) { Red = Pixel.Red; Green = Pixel.Green; Blue = Pixel.Blue;#if 0 // move color to center so can see on both white and black backgrounds Red = Red/2 + 64; Green = Green/2 + 64; Blue = Blue/2 + 64;#endif Fprintf(pFile, "%.2g %.2g %.2g %.4g %.4g colorpixel\n", (double)Red / 255, (double)Green / 255, (double)Blue / 255, ix * Scale - 0.5, iy * Scale - 0.5); } else Fprintf(pFile, "%.4g %.4g pixel\n", ix * Scale - 0.5, iy * Scale - 0.5); } }Fprintf(pFile, "grestore\n");}//-----------------------------------------------------------------------------// Write shapes one-per-page with image underneath shapevoid PsShapesImagesOnPage (int *pnPage, // io char **asImageNames, Image aImages[], // in const SHAPE *aShapes, // in int nShapes, const char *sPsFile, FILE *pPsFile, int nPsImageFlag) // in{if (nPsImageFlag) // 1=just first image, 2=all images { int nShapes1 = (nPsImageFlag > 1? nShapes: 1); InitPacifyUser(nShapes1); // pacify every 10% lprintf("\n Writing shapes to %s ", sPsFile); for (int iShape = 0; iShape < nShapes1; iShape++) { PacifyUser(iShape); PsPageHeader(pPsFile, (*pnPage)++); double PsScale = EstPsScale(aShapes[iShape], 1.5); byte *ShapeWarning = (byte *)calloc(aShapes[0].nrows(), 1); CheckShape(ShapeWarning, false, aShapes[iShape], "Shape %d", iShape); PsImage(aImages[iShape], PsScale, pPsFile, "Shape"); PsDrawMiddleCross(pPsFile, PsScale); PsAnnotatedShape(aShapes[iShape], ShapeWarning, sPsFile, pPsFile, PsScale, C_DBLUE, 0, "Shape %d over image", iShape); PsPageTitle(pPsFile, "Shape %d over %s", iShape, &asImageNames[iShape][3]); PsPageFooter(pPsFile); } lprintf("100%% "); }}//-----------------------------------------------------------------------------// Draw a small cross in the middle of the pagevoid PsDrawMiddleCross (FILE *pFile, double Scale){Fprintf(pFile, "%% Cross\n");Fprintf(pFile, "0.5 0 0 setrgbcolor\n"); // dark redFprintf(pFile, "-%.4g 0 moveto\n", Scale);Fprintf(pFile, "%.4g 0 lineto\n", Scale);Fprintf(pFile, "0 %.4g moveto\n", Scale);Fprintf(pFile, "0 -%.4g lineto\n", Scale);Fprintf(pFile, "stroke\n", Scale);};//-----------------------------------------------------------------------------void __cdecl PsSetPageHeader (const char *pArgs, ...) // args like printf{va_list pArg;va_start(pArg, pArgs);vsprintf(sgPsPageHeader, pArgs, pArg);va_end(pArg);}//-----------------------------------------------------------------------------// Draw all shapes with their whiskers in a single postscript filevoid PsAllShapes (const SHAPE aShapes[], Image aImages[], char *saTags[], int nShapes, const SHAPE &AvShape, const tLand Lands[], int nProfPoints){FILE *pPsFile; char *sPsFile = "ps/shapes.ps";pPsFile = Fopen(sPsFile, "w");int nPage = 1;PsDocHeader(pPsFile, nShapes);for (int iShape = 0; iShape < nShapes; iShape++) {#if 0 if (iShape != 0 && iShape != 65) continue;#endif // show AlignedAvShape as well -- to do this get AvShape and align it to this shape SHAPE AlignedAvShape(AvShape); AlignShape(AlignedAvShape, aShapes[iShape]); double PsScale = EstPsScale(aShapes[iShape], 1.5); PsPageShapeImage(&nPage, 1, 1, 0, aShapes[iShape], Lands, AlignedAvShape, aImages[iShape], sPsFile, pPsFile, PsScale, C_RED, 0, nProfPoints, "Shape %d %s", iShape, saTags[iShape]); PsShape(AlignedAvShape, pPsFile, PsScale, C_BLACK, 0, "AlignedMeanShape", iShape); PsPageFooter(pPsFile); }PsDocFooter(pPsFile);fclose(pPsFile);}//-----------------------------------------------------------------------------// This returns a scale that ensures that the given shapes fit into one Factor of the pagedouble EstPsScale (const SHAPE *aShapes, int nShapes, double Factor){double Min = FLT_MAX;for (int iShape = 0; iShape < nShapes; iShape++) { double Min1 = EstPsScale(aShapes[iShape], Factor); if (Min1 < Min) Min = Min1; }return Min;}double EstPsScale (const SHAPE Shape, double Factor){double xAbs = Shape.col(VX).maxAbsElem();double yAbs = Shape.col(VY).maxAbsElem();if (xAbs < 10) xAbs = 10;if (xAbs > yAbs) return CONF_PsPageWidth / (Factor * 2 * xAbs); // * 2 because need plus and minus directionselse return CONF_PsPageHeight / (Factor * 2 * yAbs);}//-----------------------------------------------------------------------------// Use some heuristics to check validity of shape. Results are warnings, not// necessarily errors but useful in practice if you make mistakes like me.// Results are clearer if displayed using PsAnnotatedShape.// TODO we be replaced with something better//// Returns results by setting bits in byte array Warnings, see WARN_ defs in headervoid CheckShape (byte Warnings[], // out bool fWriteWarnings, // in const SHAPE &Shape, const char *sMsg, int iParam, int jParam) // in{// Make sure points aren't too close - usually because user specified same point twice.// People sometimes specify first and last point twice which causes// AlignShape() to return a slight rotation, so don't do it.// The closest two points are allowed is: extent of shape divided by the const MIN_DIST_DIV// This search is O(n-squared) but fast enough in practice#define CONF_nMinDistDiv 2500 // chosen so original resistor.shape passesdouble MinDist = __max(xShapeExtent(Shape), yShapeExtent(Shape));MinDist = MinDist * MinDist / CONF_nMinDistDiv;for (int i = 0; i < Shape.nrows(); i++) for (int j = i; j < Shape.nrows(); j++) // start at j=i so don't do same point twice if (i != j // don't check against myself && fPointUsed(Shape, i) && fPointUsed(Shape, j)) { double Dist = Shape.row(i).distSquared(Shape.row(j)); if (Dist < MinDist) { Warnings[i] |= WARN_TOO_CLOSE; if (fWriteWarnings) { ngWarnings++; char s[PLEN]; sprintf(s, sMsg, iParam, jParam); Warn("%s points %d (%g,%g) and %d (%g,%g) too close? (dist %.2g min allowed %.2g)", s, i, Shape(i,VX), Shape(i,VY), j, Shape(j,VX), Shape(j,VY), sqrt(Dist), sqrt(MinDist)); } } }#if 0// Check that points go in a clockwise directionfor (i = 1; i < Shape.nrows(); i++) { if (fGeq(Shape(i, VX), Shape(i-1, VX), MinDist) && fLeq(Shape(i, VY), Shape(i-1, VY), MinDist)) continue; if (fLeq(Shape(i, VX), Shape(i-1, VX), MinDist) && fGeq(Shape(i, VY), Shape(i-1, VY), MinDist)) continue; Warnings[i] |= WARN_NOT_CLOCKWISE; if (fWriteWarnings) { ngWarnings++; char s[PLEN]; sprintf(s, sMsg, iParam, jParam); Warn("%s points %d (%g,%g) and %d (%g,%g) not clockwise?", s, i-1, Shape(i-1,VX), Shape(i-1,VY), i, Shape(i,VX), Shape(i,VY)); } }#endif}//-----------------------------------------------------------------------------void CheckShapes (byte *aWarnings[], // out: bits set for warnings bool fWriteWarnings, // in const SHAPE *aShapes, int nShapes, const char *sMsg) // in{for (int iShape = 0; iShape < nShapes; iShape++) { char s[PLEN]; sprintf(s, "%s %d", sMsg, iShape+1); // TODO don't need to do this, could just use iParam of CheckShape? CheckShape(aWarnings[iShape], fWriteWarnings, aShapes[iShape], s); }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -