【问题标题】:Create infinite parallel pattern创建无限平行图案
【发布时间】:2018-05-30 13:42:24
【问题描述】:

我想创建无限重复的线条图案。但是,线条在水平和垂直方向上都从线条的末端偏移了一些定义的间距。如下图所示:

Elemental Pattern

现在我希望这种模式在水平和垂直方向上都有偏移。模式的使用应该如图 2 所示。

现在,我正在手动执行三角函数来创建给定宽度和矩形高度的线条,但我想在 SVG 中使用 <pattern>。没有<pattern>,我很难改变渲染图案的比例。

不幸的是,我无法从任何在线教程或参考文档中找到进行偏移重复的方法。

我尝试过的:

这是我到目前为止所做的给定 S、线长、X 偏移量、Y 偏移量

  1. 创建宽高的盒子,左下角为 (0,0)
  2. 创建从 0,0 到 L,0 的第一行
  3. 从 L+S,0 到 2L+S,0 再创建一条线
  4. 一旦 (x,y) 到达框的边界 - 停止

现在通过在顶部方向传播偏移来重复 (1,4)。如果在偏移之后,您在框外:- 画一条非常大的线,如果它与框相交:从相交点开始绘制。

重复直到 2 组偏移不与框相交。我用 python 编写了所有这些并创建了<line>

不幸的是,我无法缩放它,并且我不能让矩形被图案大小的变化所填充。我正在为简单的图案渲染 100 条线。

这是我的python代码:

def cosd(angle):
    return np.cos(angle*np.pi/180.0)

def sind(angle):
    return np.sin(angle*np.pi/180.0)


class pattern():
    def __init__(self, angle, x, y, x_offset, y_offset, dashes):
        self.angle = angle
        self.p = Point(x, y)
        self.x_offset = x_offset
        self.y_offset = y_offset
        self.dashes = dashes
        self.svg_lines = []

    # Check if the origins are in the box
    def in_box(self, poly):
        if poly.encloses_point(self.p) == False:
            if len(intersection(self.p, poly)) < 1:
                return False
            else:
                return True
        else:
            return True

    def offset_me(self, direction='+'):
        """
            x offset creates vector U in direction of angle of Length = x_offset
            y offset creates vector V in direction perp of U with length of y_offset
            Adding these two vector provides new offset location 
        """
        x1 = self.p[0]
        y1 = self.p[1]
        angle = self.angle
        theta = 90 - angle 
        if direction == '-':
            theta = -1*theta
        x3 = x1 + cosd(angle)*self.x_offset + cosd(theta)*self.y_offset
        y3 = y1 + sind(angle)*self.x_offset + sind(theta)*self.y_offset
        self.p = Point(x3, y3)
        print "Offsetting in " + direction

    def draw_svg_line(self, p1, p2):
        print Segment(p1, p2)
        self.svg_lines.append(Segment(p1, p2))

    def clean_report_svg_lines(self,poly):
        rep = self.svg_lines
        result = []
        for item in rep:
            if len(intersection(item,poly)) > 0 or poly.encloses_point(item.points[0]):
                if item not in result:
                    result.append(item)

        txt = []
        for item in result:
            x1 = item.points[0][0]
            y1 = item.points[0][1]
            x2 = item.points[1][0]
            y2 = item.points[1][1]
            svg_str = '<line x1="{}" y1="{}" x2="{}" y2="{}" style="stroke:rgb(255,0,0);stroke-width:0.5" />'.format(x1,y1,x2,y2)
            txt.append(svg_str)

        return txt

    def draw_all(self, poly):

        # Draw in Positive Direction
        starter_point = self.p.copy()
        #self.draw_me(poly, direction='+')
        while poly.encloses_point(self.p):
            self.draw_me(poly, direction='+')

        self.p = starter_point
        starter_point = self.p.copy()
        #self.draw_me(poly, direction='-')
        while poly.encloses_point(self.p):
            self.draw_me(poly, direction='-')

    def draw_me(self, poly, direction='+'):
        angle = self.angle
        # Draw backwards
        my_dash = self.dashes
        if direction == '-':
            my_dash.reverse()

        for L in self.dashes:
            abs_L = abs(L)
            if L > 0:
                if direction == '-':
                    x2 = self.p[0] - cosd(angle)*abs_L
                    y2 = self.p[1] - sind(angle)*abs_L
                else:
                    x2 = self.p[0] + cosd(angle)*abs_L
                    y2 = self.p[1] + sind(angle)*abs_L
                line = Segment(self.p, Point(x2,y2))
                inter = intersection(line, poly)
                self.draw_svg_line(self.p,Point(x2,y2))
                self.p = Point(x2,y2)
            elif L == 0:
                pass
            elif L < 0:
                if direction == '-':
                    self.p = Point(self.p[0] - abs_L*cosd(angle), self.p[1] - abs_L*sind(angle))
                else:
                    self.p = Point(self.p[0] + abs_L*cosd(angle), self.p[1] + abs_L*sind(angle))      

    def print_me(self):
        print self.p
        print self.angle

    def travel(self,p,L, direction='+'):
        angle = self.angle
        x2 = p[0] + cosd(angle)*L
        y2 = p[1] + sind(angle)*L
        if direction == '-':
            x2 = p[0] - cosd(angle)*L
            y2 = p[1] - sind(angle)*L
        p2 = Point(x2,y2)
        return p2

    def get_starting_point(self, poly):
        # Its already in box
        if self.in_box(poly):
            return True, self.p

        length = sum([abs(x) for x in self.dashes])
        p2 = self.travel(self.p, length)
        if poly.encloses_point(p2):
            return True, p2

        if intersection(Line(self.p, p2),poly):
            # It has intersections but which way?
            i = intersection(Line(self.p, p2),poly)
            print type(i[0])
            if isinstance(i[0], sympy.geometry.point.Point2D):
                i = Segment(i[0], i[1])
            else:
                i = i[0]
            p_midpoint = i.midpoint
            print p_midpoint[0]
            direction = '+'
            if p_midpoint[0] - self.p[0] <= 0:
                direction = '-'
            # Now we know which way it is go back until we hit....
            while len(intersection(Segment(self.p, p2),poly)) < 1:
                self.p = self.travel(self.p, length,direction)
                p2 = self.travel(self.p, length,direction)
            return True, p2
        else:
            return False, None


    # Get origins to the box 
    def offset_draw(self, poly):
        starting_p = self.p.copy()
        possible, self.p = self.get_starting_point(poly)
        self.draw_all(poly)

        # Positive Draw
        while possible:
            self.draw_all(poly)
            self.offset_me(direction='+')
            possible, self.p = self.get_starting_point(poly)

        self.p = starting_p
        print self.p
        self.offset_me(direction='-')
        possible, self.p = self.get_starting_point(poly)

        # Negetive Draw
        while possible:
            self.draw_all(poly)
            self.offset_me(direction='-')
            possible, self.p = self.get_starting_point(poly)        

我将 python 代码(行元素)的粘贴结果复制到 svg 模式标签中: Codepen example

【问题讨论】:

  • 我想我会编辑我迄今为止尝试过的内容......
  • 这将是在本网站上获得高质量答案的正确方法。
  • 我写了我的尝试
  • 任何对编码一无所知的人都会写这个,@pozza。我们在这里只帮助程序员。否则,Stack Overflow 会变成 “给我 teh codez,plez” 网站,这是我们想要避免的。
  • @AndreiGheorghiu 在那里!我还能做什么?

标签: html css d3.js canvas svg


【解决方案1】:

既然你标记了这个d3,我认为d3 答案是可以接受的?无论如何,它将向您展示如何构建模式,并且应该可以轻松转换为 python

<!DOCTYPE html>
<html>

  <head>
    <script data-require="d3@4.0.0" data-semver="4.0.0" src="https://d3js.org/d3.v4.min.js"></script>
  </head>

  <body>
    <script>
      
      var width = 1000,
          height = 1000,
          offsetX = 25,
          offsetY = 25,
          lineLength = 75,
          strokeWidth = 3;
      
      var svg = d3.select('body')
        .append('svg')
        .attr('width', width)
        .attr('height', height);
        
      var p = svg.append('pattern')
        .attr('id', 'myPattern')
        .attr('x', 0)
        .attr('y', 0)
        .attr('width', (offsetX + lineLength) / width)
        .attr('height', (offsetY * 2) / height);
      
      p.append("line")
        .attr("x1", 0)
        .attr("x2", lineLength)
        .attr("y1", strokeWidth)
        .attr("y2", strokeWidth)
        .style("stroke-width", strokeWidth)
        .style("stroke", "black");
        
      p.append("line")
        .attr("x1", offsetX)
        .attr("x2", lineLength + offsetX)
        .attr("y1", offsetY + strokeWidth)
        .attr("y2", offsetY + strokeWidth)
        .style("stroke-width", strokeWidth)
        .style("stroke", "black");
        
      p.append("circle")
        .attr("cx", lineLength)
        .attr("cy", strokeWidth)
        .attr("r", strokeWidth);
        
      p.append("circle")
        .attr("cx", strokeWidth)
        .attr("cy", strokeWidth)
        .attr("r", strokeWidth);
        
      p.append("circle")
        .attr("cx", offsetX)
        .attr("cy", offsetY + strokeWidth)
        .attr("r", strokeWidth);
        
      p.append("circle")
        .attr("cx", lineLength + offsetX - strokeWidth)
        .attr("cy", offsetY + strokeWidth)
        .attr("r", strokeWidth);
        
      svg.append("rect")
        .attr("width", width)
        .attr("height", height)
        .attr("fill","url(#myPattern)");

    </script>
  </body>

</html>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-10-12
    • 1970-01-01
    • 2019-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-01
    • 2015-01-06
    相关资源
    最近更新 更多