| 1695 | #define CURVE_SIN_LIMIT 0.3 |
| 1696 | |
| 1697 | shapeObj *msOffsetPolyline(shapeObj *p, double offsetx, double offsety) { |
| 1698 | int i, j, first,idx; |
| 1699 | |
| 1700 | shapeObj *ret = (shapeObj*)msSmallMalloc(sizeof(shapeObj)); |
| 1701 | msInitShape(ret); |
| 1702 | ret->numlines = p->numlines; |
| 1703 | ret->line=(lineObj*)msSmallMalloc(sizeof(lineObj)*ret->numlines); |
| 1704 | for(i=0;i<ret->numlines;i++) { |
| 1705 | ret->line[i].numpoints=p->line[i].numpoints; |
| 1706 | ret->line[i].point=(pointObj*)msSmallMalloc(sizeof(pointObj)*ret->line[i].numpoints); |
| 1707 | } |
| 1708 | |
| 1709 | if(offsety == -99) { /* complex calculations */ |
| 1710 | for (i = 0; i < p->numlines; i++) { |
| 1711 | pointObj old_pt, old_diffdir, old_offdir; |
| 1712 | /* initialize old_offdir and old_diffdir, as gcc isn't smart enough to see that it |
| 1713 | * is not an error to do so, and prints a warning */ |
| 1714 | old_offdir.x=old_offdir.y=old_diffdir.x=old_diffdir.y = 0; |
| 1715 | |
| 1716 | idx=0; |
| 1717 | first = 1; |
| 1718 | |
| 1719 | /* saved metrics of the last processed point */ |
| 1720 | if (p->line[i].numpoints>0) |
| 1721 | old_pt=p->line[i].point[0]; |
| 1722 | for(j=1; j<p->line[i].numpoints; j++) { |
| 1723 | const pointObj pt = p->line[i].point[j]; /* place of the point */ |
| 1724 | const pointObj diffdir = point_norm(point_diff(pt,old_pt)); /* direction of the line */ |
| 1725 | const pointObj offdir = point_rotz90(diffdir); /* direction where the distance between the line and the offset is measured */ |
| 1726 | pointObj offpt; /* this will be the corner point of the offset line */ |
| 1727 | |
| 1728 | /* offset line points computation */ |
| 1729 | if(first == 1) { /* first point */ |
| 1730 | first = 0; |
| 1731 | offpt = point_sum(old_pt,point_mul(offdir,offsetx)); |
| 1732 | } else { /* middle points */ |
| 1733 | /* curve is the angle of the last and the current line's direction (supplementary angle of the shape's inner angle) */ |
| 1734 | double sin_curve = point_cross(diffdir,old_diffdir); |
| 1735 | double cos_curve = point_cross(old_offdir,diffdir); |
| 1736 | if ((-1.0)*CURVE_SIN_LIMIT < sin_curve && sin_curve < CURVE_SIN_LIMIT) { |
| 1737 | /* do not calculate 1/sin, instead use a corner point approximation: average of the last and current offset direction and length */ |
| 1738 | |
| 1739 | /* |
| 1740 | ** TODO: fair for obtuse inner angles, however, positive and negative |
| 1741 | ** acute inner angles would need special handling - similar to LINECAP |
| 1742 | ** to avoid drawing of long spikes |
| 1743 | */ |
| 1744 | offpt = point_sum(old_pt, point_mul(point_sum(offdir, old_offdir),0.5*offsetx)); |
| 1745 | } else { |
| 1746 | double base_shift = -1.0*(1.0+cos_curve)/sin_curve; |
| 1747 | offpt = point_sum(old_pt, point_mul(point_sum(point_mul(diffdir,base_shift),offdir), offsetx)); |
| 1748 | } |
| 1749 | } |
| 1750 | ret->line[i].point[idx]=offpt; |
| 1751 | idx++; |
| 1752 | old_pt=pt; old_diffdir=diffdir; old_offdir=offdir; |
| 1753 | } |
| 1754 |
no test coverage detected